@speakableio/core 1.0.0 → 1.0.2

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.
Files changed (42) hide show
  1. package/dist/analytics.d.mts +38 -1
  2. package/dist/analytics.js +117 -1
  3. package/dist/analytics.js.map +1 -1
  4. package/dist/index.native.js +15 -1
  5. package/dist/index.native.js.map +1 -1
  6. package/dist/index.native.mjs +15 -1
  7. package/dist/index.native.mjs.map +1 -1
  8. package/dist/index.web.js +15 -1
  9. package/dist/index.web.js.map +1 -1
  10. package/package.json +2 -2
  11. package/dist/analytics-Bj2i88Zk.d.ts +0 -89
  12. package/dist/analytics.d.ts +0 -88
  13. package/dist/assignment.constants-BIKM6fYi.d.ts +0 -32
  14. package/dist/assignment.model-BRS4h8gX.d.ts +0 -301
  15. package/dist/assignment.model-Bc61gBHl.d.ts +0 -302
  16. package/dist/assignment.model-Bm9gE2YK.d.ts +0 -301
  17. package/dist/card.constants-DhKFipX3.d.ts +0 -54
  18. package/dist/const.d.ts +0 -261
  19. package/dist/const.js +0 -503
  20. package/dist/const.js.map +0 -1
  21. package/dist/everything.d.ts +0 -1348
  22. package/dist/everything.js +0 -3509
  23. package/dist/everything.js.map +0 -1
  24. package/dist/hooks.d.ts +0 -911
  25. package/dist/hooks.js +0 -2699
  26. package/dist/hooks.js.map +0 -1
  27. package/dist/index.web-DNYJV_41.d.ts +0 -469
  28. package/dist/index.web.d.ts +0 -471
  29. package/dist/models.d.ts +0 -56
  30. package/dist/models.js +0 -52
  31. package/dist/models.js.map +0 -1
  32. package/dist/notification.constants-B72fb734.d.ts +0 -21
  33. package/dist/repos.d.ts +0 -209
  34. package/dist/repos.js +0 -453
  35. package/dist/repos.js.map +0 -1
  36. package/dist/speakable-plans-BjWWEWrQ.d.ts +0 -72
  37. package/dist/speakable-plans-DR1cQ6IK.d.ts +0 -92
  38. package/dist/speakable-plans-Dq9nRefI.d.ts +0 -72
  39. package/dist/utils.d.ts +0 -121
  40. package/dist/utils.js +0 -646
  41. package/dist/utils.js.map +0 -1
  42. package/dist/web.constants-qmx4rGyO.d.ts +0 -26
@@ -1,3509 +0,0 @@
1
- // src/constants/analytics.constants.ts
2
- var ANALYTICS_EVENT_TYPES = {
3
- VOICE_SUCCESS: "voice_success",
4
- VOICE_FAIL: "voice_fail",
5
- RESPOND_CARD_SUCCESS: "respond_card_success",
6
- RESPOND_CARD_FAIL: "respond_card_fail",
7
- RESPOND_WRITE_CARD_SUCCESS: "respond_write_card_success",
8
- RESPOND_WRITE_CARD_FAIL: "respond_write_card_fail",
9
- RESPOND_WRITE_CARD_SUBMITTED: "respond_write_card_submitted",
10
- RESPOND_WRITE_CARD_ERROR: "respond_write_card_error",
11
- RESPOND_CARD_ERROR: "respond_card_error",
12
- RESPOND_CARD_SUBMITTED: "respond_card_submitted",
13
- RESPOND_FREE_PLAN: "respond_free_plan",
14
- RESPOND_WRITE_FREE_PLAN: "respond_write_free_plan",
15
- SUBMISSION: "assignment_submitted",
16
- ASSIGNMENT_STARTED: "assignment_started",
17
- CREATE_ASSIGNMENT: "create_assignment",
18
- MC_SUCCESS: "multiple_choice_success",
19
- MC_FAIL: "multiple_choice_fail",
20
- MC_ERROR: "multiple_choice_error",
21
- ACTFL_LEVEL: "actfl_level",
22
- WIDA_LEVEL: "wida_level"
23
- };
24
-
25
- // src/constants/speakable-plans.ts
26
- var FEEDBACK_PLANS = {
27
- FEEDBACK_TRANSCRIPT: "FEEDBACK_TRANSCRIPT",
28
- // Transcript from the audio
29
- FEEDBACK_SUMMARY: "FEEDBACK_SUMMARY",
30
- // Chatty summary (Free plan)
31
- FEEDBACK_GRAMMAR_INSIGHTS: "FEEDBACK_GRAMMAR_INSIGHTS",
32
- // Grammar insights
33
- FEEDBACK_SUGGESTED_RESPONSE: "FEEDBACK_SUGGESTED_RESPONSE",
34
- // Suggested Response
35
- FEEDBACK_RUBRIC: "FEEDBACK_RUBRIC",
36
- // Suggested Response
37
- FEEDBACK_GRADING_STANDARDS: "FEEDBACK_GRADING_STANDARDS",
38
- // ACTFL / WIDA Estimate
39
- FEEDBACK_TARGET_LANGUAGE: "FEEDBACK_TARGET_LANGUAGE",
40
- // Ability to set the feedback language to the target language of the student
41
- FEEDBACK_DISABLE_ALLOW_RETRIES: "FEEDBACK_DISABLE_ALLOW_RETRIES"
42
- // Turn of allow retries
43
- };
44
- var AUTO_GRADING_PLANS = {
45
- AUTO_GRADING_PASS_FAIL: "AUTO_GRADING_PASS_FAIL",
46
- // Pass / fail grading
47
- AUTO_GRADING_RUBRICS: "AUTO_GRADING_RUBRICS",
48
- // Autograded rubrics
49
- AUTO_GRADING_STANDARDS_BASED: "AUTO_GRADING_STANDARDS_BASED"
50
- // Standards based grading
51
- };
52
- var COMMENTS_PLANS = {
53
- COMMENTS_SUGGESTIONS: "COMMENTS_SUGGESTIONS"
54
- // Comment suggestions
55
- };
56
- var AI_ASSISTANT_PLANS = {
57
- AI_ASSISTANT_DOCUMENT_UPLOADS: "AI_ASSISTANT_DOCUMENT_UPLOADS",
58
- // Allow document uploading
59
- AI_ASSISTANT_UNLIMITED_USE: "AI_ASSISTANT_UNLIMITED_USE"
60
- // Allow unlimited use of AI assistant. Otherwise, limits are used.
61
- };
62
- var ASSIGNMENT_SETTINGS_PLANS = {
63
- ASSESSMENTS: "ASSESSMENTS",
64
- // Ability to create assessment assignment types
65
- GOOGLE_CLASSROOM_GRADE_PASSBACK: "GOOGLE_CLASSROOM_GRADE_PASSBACK"
66
- // Assignment scores can sync with classroom
67
- };
68
- var ANALYTICS_PLANS = {
69
- ANALYTICS_GRADEBOOK: "ANALYTICS_GRADEBOOK",
70
- // Access to the gradebook page
71
- ANALYTICS_CLASSROOM_ANALYTICS: "ANALYTICS_CLASSROOM_ANALYTICS",
72
- // Access to the classroom analytics page
73
- ANALYTICS_STUDENT_PROGRESS_REPORTS: "ANALYTICS_STUDENT_PROGRESS_REPORTS",
74
- // Access to the panel that shows an individual student's progress and assignments
75
- ANALYTICS_ASSIGNMENT_RESULTS: "ANALYTICS_ASSIGNMENT_RESULTS",
76
- // Access to the assigment RESULTS page
77
- ANALYTICS_ORGANIZATION: "ANALYTICS_ORGANIZATION"
78
- // Access to the organization analytics panel (for permitted admins)
79
- };
80
- var SPACES_PLANS = {
81
- SPACES_CREATE_SPACE: "SPACES_CREATE_SPACE",
82
- // Ability to create spaces
83
- SPACES_CHECK_POINTS: "SPACES_CHECK_POINTS"
84
- // Feature not available yet. Ability to create checkpoints for spaces for data aggregation
85
- };
86
- var DISCOVER_PLANS = {
87
- DISCOVER_ORGANIZATION_LIBRARY: "DISCOVER_ORGANIZATION_LIBRARY"
88
- // Access to the organizations shared library
89
- };
90
- var INTEGRATIONS_PLANS = {
91
- INTEGRATIONS_LTI: "INTEGRATIONS_LTI"
92
- //Access to all LTI integrations (Canvas, Blackboard, Schoology, etc)
93
- };
94
- var MEDIA_AREA_PLANS = {
95
- MEDIA_AREA_DOCUMENT_UPLOAD: "MEDIA_AREA_DOCUMENT_UPLOAD",
96
- MEDIA_AREA_AUDIO_FILES: "MEDIA_AREA_AUDIO_FILES"
97
- };
98
- var FREE_PLAN = [];
99
- var TEACHER_PRO_PLAN = [
100
- FEEDBACK_PLANS.FEEDBACK_TRANSCRIPT,
101
- FEEDBACK_PLANS.FEEDBACK_SUMMARY,
102
- FEEDBACK_PLANS.FEEDBACK_TARGET_LANGUAGE,
103
- AUTO_GRADING_PLANS.AUTO_GRADING_PASS_FAIL,
104
- ANALYTICS_PLANS.ANALYTICS_GRADEBOOK,
105
- SPACES_PLANS.SPACES_CREATE_SPACE
106
- // AUTO_GRADING_PLANS.AUTO_GRADING_STANDARDS_BASED,
107
- ];
108
- var SCHOOL_STARTER = [
109
- FEEDBACK_PLANS.FEEDBACK_TRANSCRIPT,
110
- FEEDBACK_PLANS.FEEDBACK_SUMMARY,
111
- FEEDBACK_PLANS.FEEDBACK_GRAMMAR_INSIGHTS,
112
- FEEDBACK_PLANS.FEEDBACK_SUGGESTED_RESPONSE,
113
- FEEDBACK_PLANS.FEEDBACK_RUBRIC,
114
- FEEDBACK_PLANS.FEEDBACK_GRADING_STANDARDS,
115
- FEEDBACK_PLANS.FEEDBACK_DISABLE_ALLOW_RETRIES,
116
- FEEDBACK_PLANS.FEEDBACK_TARGET_LANGUAGE,
117
- AUTO_GRADING_PLANS.AUTO_GRADING_PASS_FAIL,
118
- AUTO_GRADING_PLANS.AUTO_GRADING_RUBRICS,
119
- AUTO_GRADING_PLANS.AUTO_GRADING_STANDARDS_BASED,
120
- AI_ASSISTANT_PLANS.AI_ASSISTANT_DOCUMENT_UPLOADS,
121
- AI_ASSISTANT_PLANS.AI_ASSISTANT_UNLIMITED_USE,
122
- // ASSIGNMENT_SETTINGS_PLANS.ASSESSMENTS,
123
- ASSIGNMENT_SETTINGS_PLANS.GOOGLE_CLASSROOM_GRADE_PASSBACK,
124
- ANALYTICS_PLANS.ANALYTICS_GRADEBOOK,
125
- ANALYTICS_PLANS.ANALYTICS_STUDENT_PROGRESS_REPORTS,
126
- ANALYTICS_PLANS.ANALYTICS_CLASSROOM_ANALYTICS,
127
- // ANALYTICS_PLANS.ANALYTICS_ORGANIZATION,
128
- SPACES_PLANS.SPACES_CREATE_SPACE,
129
- SPACES_PLANS.SPACES_CHECK_POINTS,
130
- // DISCOVER_PLANS.DISCOVER_ORGANIZATION_LIBRARY,
131
- MEDIA_AREA_PLANS.MEDIA_AREA_DOCUMENT_UPLOAD,
132
- MEDIA_AREA_PLANS.MEDIA_AREA_AUDIO_FILES
133
- ];
134
- var ORGANIZATION_PLAN = [
135
- FEEDBACK_PLANS.FEEDBACK_TRANSCRIPT,
136
- FEEDBACK_PLANS.FEEDBACK_SUMMARY,
137
- FEEDBACK_PLANS.FEEDBACK_GRAMMAR_INSIGHTS,
138
- FEEDBACK_PLANS.FEEDBACK_SUGGESTED_RESPONSE,
139
- FEEDBACK_PLANS.FEEDBACK_RUBRIC,
140
- FEEDBACK_PLANS.FEEDBACK_GRADING_STANDARDS,
141
- FEEDBACK_PLANS.FEEDBACK_DISABLE_ALLOW_RETRIES,
142
- FEEDBACK_PLANS.FEEDBACK_TARGET_LANGUAGE,
143
- AUTO_GRADING_PLANS.AUTO_GRADING_PASS_FAIL,
144
- AUTO_GRADING_PLANS.AUTO_GRADING_RUBRICS,
145
- AUTO_GRADING_PLANS.AUTO_GRADING_STANDARDS_BASED,
146
- AI_ASSISTANT_PLANS.AI_ASSISTANT_DOCUMENT_UPLOADS,
147
- AI_ASSISTANT_PLANS.AI_ASSISTANT_UNLIMITED_USE,
148
- ASSIGNMENT_SETTINGS_PLANS.ASSESSMENTS,
149
- ASSIGNMENT_SETTINGS_PLANS.GOOGLE_CLASSROOM_GRADE_PASSBACK,
150
- ANALYTICS_PLANS.ANALYTICS_GRADEBOOK,
151
- ANALYTICS_PLANS.ANALYTICS_STUDENT_PROGRESS_REPORTS,
152
- ANALYTICS_PLANS.ANALYTICS_CLASSROOM_ANALYTICS,
153
- ANALYTICS_PLANS.ANALYTICS_ORGANIZATION,
154
- SPACES_PLANS.SPACES_CREATE_SPACE,
155
- SPACES_PLANS.SPACES_CHECK_POINTS,
156
- DISCOVER_PLANS.DISCOVER_ORGANIZATION_LIBRARY,
157
- MEDIA_AREA_PLANS.MEDIA_AREA_DOCUMENT_UPLOAD,
158
- MEDIA_AREA_PLANS.MEDIA_AREA_AUDIO_FILES
159
- ];
160
- var SpeakablePlanTypes = {
161
- basic: "basic",
162
- teacher_pro: "teacher_pro",
163
- school_starter: "school_starter",
164
- organization: "organization",
165
- // OLD PLANS
166
- starter: "starter",
167
- growth: "growth",
168
- professional: "professional"
169
- };
170
- var SpeakablePermissionsMap = {
171
- [SpeakablePlanTypes.basic]: FREE_PLAN,
172
- [SpeakablePlanTypes.starter]: TEACHER_PRO_PLAN,
173
- [SpeakablePlanTypes.teacher_pro]: TEACHER_PRO_PLAN,
174
- [SpeakablePlanTypes.growth]: ORGANIZATION_PLAN,
175
- [SpeakablePlanTypes.professional]: ORGANIZATION_PLAN,
176
- [SpeakablePlanTypes.organization]: ORGANIZATION_PLAN,
177
- [SpeakablePlanTypes.school_starter]: SCHOOL_STARTER
178
- };
179
- var SpeakablePlanHierarchy = [
180
- SpeakablePlanTypes.basic,
181
- SpeakablePlanTypes.starter,
182
- SpeakablePlanTypes.teacher_pro,
183
- SpeakablePlanTypes.growth,
184
- SpeakablePlanTypes.professional,
185
- SpeakablePlanTypes.school_starter,
186
- SpeakablePlanTypes.organization
187
- ];
188
-
189
- // src/constants/web.constants.ts
190
- var WEB_BASE_URL = "https://app.speakable.io";
191
-
192
- // src/domains/cards/card.model.ts
193
- var ActivityPageType = /* @__PURE__ */ ((ActivityPageType2) => {
194
- ActivityPageType2["READ_REPEAT"] = "READ_REPEAT";
195
- ActivityPageType2["VIDEO"] = "VIDEO";
196
- ActivityPageType2["TEXT"] = "TEXT";
197
- ActivityPageType2["READ_RESPOND"] = "READ_RESPOND";
198
- ActivityPageType2["FREE_RESPONSE"] = "FREE_RESPONSE";
199
- ActivityPageType2["REPEAT"] = "REPEAT";
200
- ActivityPageType2["RESPOND"] = "RESPOND";
201
- ActivityPageType2["RESPOND_WRITE"] = "RESPOND_WRITE";
202
- ActivityPageType2["TEXT_TO_SPEECH"] = "TEXT_TO_SPEECH";
203
- ActivityPageType2["MULTIPLE_CHOICE"] = "MULTIPLE_CHOICE";
204
- ActivityPageType2["PODCAST"] = "PODCAST";
205
- ActivityPageType2["MEDIA_PAGE"] = "MEDIA_PAGE";
206
- ActivityPageType2["WRITE"] = "WRITE";
207
- ActivityPageType2["SHORT_ANSWER"] = "SHORT_ANSWER";
208
- ActivityPageType2["SHORT_STORY"] = "SHORT_STORY";
209
- ActivityPageType2["SPEAK"] = "SPEAK";
210
- ActivityPageType2["CONVERSATION"] = "CONVERSATION";
211
- ActivityPageType2["CONVERSATION_WRITE"] = "CONVERSATION_WRITE";
212
- ActivityPageType2["DIALOGUE"] = "DIALOGUE";
213
- ActivityPageType2["INSTRUCTION"] = "INSTRUCTION";
214
- ActivityPageType2["LISTEN"] = "LISTEN";
215
- ActivityPageType2["READ"] = "READ";
216
- ActivityPageType2["ANSWER"] = "ANSWER";
217
- return ActivityPageType2;
218
- })(ActivityPageType || {});
219
- var RESPOND_PAGE_ACTIVITY_TYPES = [
220
- "READ_RESPOND" /* READ_RESPOND */,
221
- "RESPOND" /* RESPOND */,
222
- "RESPOND_WRITE" /* RESPOND_WRITE */,
223
- "FREE_RESPONSE" /* FREE_RESPONSE */
224
- ];
225
- var MULTIPLE_CHOICE_PAGE_ACTIVITY_TYPES = ["MULTIPLE_CHOICE" /* MULTIPLE_CHOICE */];
226
- var REPEAT_PAGE_ACTIVITY_TYPES = ["READ_REPEAT" /* READ_REPEAT */, "REPEAT" /* REPEAT */];
227
- var RESPOND_WRITE_PAGE_ACTIVITY_TYPES = [
228
- "RESPOND_WRITE" /* RESPOND_WRITE */,
229
- "FREE_RESPONSE" /* FREE_RESPONSE */
230
- ];
231
- var RESPOND_AUDIO_PAGE_ACTIVITY_TYPES = [
232
- "RESPOND" /* RESPOND */,
233
- "READ_RESPOND" /* READ_RESPOND */
234
- ];
235
-
236
- // src/providers/SpeakableProvider.tsx
237
- import { createContext, useContext, useEffect, useState } from "react";
238
- import { jsx } from "react/jsx-runtime";
239
- var FsCtx = createContext(null);
240
- function SpeakableProvider({
241
- user,
242
- children,
243
- queryClient,
244
- permissions,
245
- fsClient
246
- }) {
247
- const [speakableApi, setSpeakableApi] = useState(null);
248
- useEffect(() => {
249
- setSpeakableApi(fsClient);
250
- }, [fsClient]);
251
- if (!speakableApi) return null;
252
- return /* @__PURE__ */ jsx(
253
- FsCtx.Provider,
254
- {
255
- value: {
256
- speakableApi,
257
- queryClient,
258
- user,
259
- permissions
260
- },
261
- children
262
- }
263
- );
264
- }
265
- function useSpeakableApi() {
266
- const ctx = useContext(FsCtx);
267
- if (!ctx) throw new Error("useSpeakableApi must be used within a SpeakableProvider");
268
- return ctx;
269
- }
270
-
271
- // src/domains/assignment/hooks/assignment.hooks.ts
272
- import { useQuery } from "@tanstack/react-query";
273
- var assignmentQueryKeys = {
274
- all: ["assignments"],
275
- byId: (id) => [...assignmentQueryKeys.all, id],
276
- list: () => [...assignmentQueryKeys.all, "list"]
277
- };
278
- function useAssignment({
279
- assignmentId,
280
- enabled = true,
281
- analyticType,
282
- userId
283
- }) {
284
- const { speakableApi } = useSpeakableApi();
285
- return useQuery({
286
- queryKey: assignmentQueryKeys.byId(assignmentId),
287
- queryFn: () => speakableApi.assignmentRepo.getAssignment({
288
- assignmentId,
289
- analyticType,
290
- currentUserId: userId
291
- }),
292
- enabled
293
- });
294
- }
295
-
296
- // src/domains/assignment/hooks/score-hooks.ts
297
- import { useMutation, useQuery as useQuery2 } from "@tanstack/react-query";
298
-
299
- // src/utils/debounce.utils.ts
300
- function debounce(func, waitFor) {
301
- let timeoutId;
302
- return (...args) => new Promise((resolve, reject) => {
303
- if (timeoutId) {
304
- clearTimeout(timeoutId);
305
- }
306
- timeoutId = setTimeout(async () => {
307
- try {
308
- const result = await func(...args);
309
- resolve(result);
310
- } catch (error) {
311
- reject(error);
312
- }
313
- }, waitFor);
314
- });
315
- }
316
-
317
- // src/lib/tanstack/handle-optimistic-update-query.ts
318
- var handleOptimisticUpdate = async ({
319
- queryClient,
320
- queryKey,
321
- newData
322
- }) => {
323
- await queryClient.cancelQueries({
324
- queryKey
325
- });
326
- const previousData = queryClient.getQueryData(queryKey);
327
- if (previousData === void 0) {
328
- queryClient.setQueryData(queryKey, newData);
329
- } else {
330
- queryClient.setQueryData(queryKey, { ...previousData, ...newData });
331
- }
332
- return { previousData };
333
- };
334
-
335
- // src/hooks/usePermissions.ts
336
- var usePermissions = () => {
337
- const { permissions } = useSpeakableApi();
338
- const has = (permission) => {
339
- var _a;
340
- return (_a = permissions.permissions) == null ? void 0 : _a.includes(permission);
341
- };
342
- return {
343
- plan: permissions.plan,
344
- permissionsLoaded: permissions.loaded,
345
- isStripePlan: permissions.isStripePlan,
346
- refreshDate: permissions.refreshDate,
347
- isInstitutionPlan: permissions.isInstitutionPlan,
348
- subscriptionId: permissions.subscriptionId,
349
- contact: permissions.contact,
350
- hasGradebook: has(ANALYTICS_PLANS.ANALYTICS_GRADEBOOK),
351
- hasGoogleClassroomGradePassback: has(ASSIGNMENT_SETTINGS_PLANS.GOOGLE_CLASSROOM_GRADE_PASSBACK),
352
- hasAssessments: has(ASSIGNMENT_SETTINGS_PLANS.ASSESSMENTS),
353
- hasSectionAnalytics: has(ANALYTICS_PLANS.ANALYTICS_CLASSROOM_ANALYTICS),
354
- hasStudentReports: has(ANALYTICS_PLANS.ANALYTICS_STUDENT_PROGRESS_REPORTS),
355
- permissions: permissions || [],
356
- hasStudentPortfolios: permissions.hasStudentPortfolios,
357
- isFreeOrgTrial: permissions.type === "free_org_trial",
358
- freeOrgTrialExpired: permissions.freeOrgTrialExpired
359
- };
360
- };
361
- var usePermissions_default = usePermissions;
362
-
363
- // src/lib/firebase/api.ts
364
- var FirebaseAPI = class _FirebaseAPI {
365
- // eslint-disable-next-line @typescript-eslint/no-empty-function
366
- constructor() {
367
- this.config = null;
368
- }
369
- static getInstance() {
370
- if (!_FirebaseAPI.instance) {
371
- _FirebaseAPI.instance = new _FirebaseAPI();
372
- }
373
- return _FirebaseAPI.instance;
374
- }
375
- initialize(config) {
376
- this.config = config;
377
- }
378
- get db() {
379
- if (!this.config) throw new Error("Firebase API not initialized");
380
- return this.config.db;
381
- }
382
- get helpers() {
383
- if (!this.config) throw new Error("Firebase API not initialized");
384
- return this.config.helpers;
385
- }
386
- get httpsCallable() {
387
- var _a;
388
- return (_a = this.config) == null ? void 0 : _a.httpsCallable;
389
- }
390
- logEvent(name, data) {
391
- var _a;
392
- (_a = this.config) == null ? void 0 : _a.logEvent(name, data);
393
- }
394
- accessQueryConstraints() {
395
- const { query: query3, orderBy: orderBy3, limit: limit3, startAt: startAt3, startAfter: startAfter3, endAt: endAt3, endBefore: endBefore3, where: where3, increment: increment3 } = this.helpers;
396
- return {
397
- query: query3,
398
- orderBy: orderBy3,
399
- limit: limit3,
400
- startAt: startAt3,
401
- startAfter: startAfter3,
402
- endAt: endAt3,
403
- endBefore: endBefore3,
404
- where: where3,
405
- increment: increment3
406
- };
407
- }
408
- accessHelpers() {
409
- const { doc: doc3, collection: collection3, writeBatch: writeBatch3, serverTimestamp: serverTimestamp3, setDoc: setDoc3 } = this.helpers;
410
- return {
411
- doc: (path) => doc3(this.db, path),
412
- collection: (path) => collection3(this.db, path),
413
- writeBatch: () => writeBatch3(this.db),
414
- serverTimestamp: serverTimestamp3,
415
- setDoc: setDoc3
416
- };
417
- }
418
- async getDoc(path) {
419
- const { getDoc: getDoc3, doc: doc3 } = this.helpers;
420
- const docRef = doc3(this.db, path);
421
- const docSnap = await getDoc3(docRef);
422
- const data = docSnap.exists() ? {
423
- ...docSnap.data(),
424
- id: docSnap.id
425
- } : null;
426
- return {
427
- id: docSnap.id,
428
- data
429
- };
430
- }
431
- async getDocs(path, ...queryConstraints) {
432
- const { getDocs: getDocs3, query: query3, collection: collection3 } = this.helpers;
433
- const collectionRef = collection3(this.db, path);
434
- const q = queryConstraints.length > 0 ? query3(collectionRef, ...queryConstraints) : collectionRef;
435
- const querySnapshot = await getDocs3(q);
436
- const data = querySnapshot.docs.map((doc3) => ({
437
- data: doc3.data(),
438
- id: doc3.id
439
- }));
440
- return {
441
- data,
442
- querySnapshot,
443
- empty: querySnapshot.empty
444
- };
445
- }
446
- async addDoc(path, data) {
447
- const { addDoc: addDoc3, collection: collection3 } = this.helpers;
448
- const collectionRef = collection3(this.db, path);
449
- const docRef = await addDoc3(collectionRef, data);
450
- return {
451
- ...data,
452
- id: docRef.id
453
- };
454
- }
455
- async setDoc(path, data, options = {}) {
456
- const { setDoc: setDoc3, doc: doc3 } = this.helpers;
457
- const docRef = doc3(this.db, path);
458
- await setDoc3(docRef, data, options);
459
- }
460
- async updateDoc(path, data) {
461
- const { updateDoc: updateDoc3, doc: doc3 } = this.helpers;
462
- const docRef = doc3(this.db, path);
463
- await updateDoc3(docRef, data);
464
- }
465
- async deleteDoc(path) {
466
- const { deleteDoc: deleteDoc3, doc: doc3 } = this.helpers;
467
- const docRef = doc3(this.db, path);
468
- await deleteDoc3(docRef);
469
- }
470
- async runTransaction(updateFunction) {
471
- const { runTransaction: runTransaction3 } = this.helpers;
472
- return runTransaction3(this.db, updateFunction);
473
- }
474
- async runBatch(operations) {
475
- const { writeBatch: writeBatch3 } = this.helpers;
476
- const batch = writeBatch3(this.db);
477
- await Promise.all(operations.map((op) => op()));
478
- await batch.commit();
479
- }
480
- writeBatch() {
481
- const { writeBatch: writeBatch3 } = this.helpers;
482
- const batch = writeBatch3(this.db);
483
- return batch;
484
- }
485
- };
486
- var api = FirebaseAPI.getInstance();
487
-
488
- // src/hooks/useGoogleClassroom.ts
489
- var useGoogleClassroom = () => {
490
- const submitAssignmentToGoogleClassroom = async ({
491
- assignment,
492
- scores,
493
- googleUserId = null
494
- // optional to override the user's googleUserId
495
- }) => {
496
- var _a, _b, _c;
497
- try {
498
- const { googleClassroomUserId = null } = scores;
499
- const googleId = googleUserId || googleClassroomUserId;
500
- if (!googleId)
501
- return {
502
- error: true,
503
- message: "No Google Classroom ID found"
504
- };
505
- const { courseWorkId, maxPoints, owners, courseId } = assignment;
506
- const draftGrade = (scores == null ? void 0 : scores.score) ? (scores == null ? void 0 : scores.score) / 100 * maxPoints : 0;
507
- const result = await ((_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "submitAssignmentToGoogleClassroomV2")) == null ? void 0 : _c({
508
- teacherId: owners[0],
509
- courseId,
510
- courseWorkId,
511
- userId: googleId,
512
- draftGrade
513
- }));
514
- return result;
515
- } catch (error) {
516
- if (error instanceof Error) {
517
- return { error: true, message: error.message };
518
- }
519
- return { error: true, message: "Unknown error" };
520
- }
521
- };
522
- return {
523
- submitAssignmentToGoogleClassroom
524
- };
525
- };
526
-
527
- // src/lib/firebase/firebase-analytics/grading-standard.ts
528
- var logGradingStandardLog = (data) => {
529
- var _a, _b, _c;
530
- if (data.courseId && data.type && data.level) {
531
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "handleCouresAnalyticsEvent")) == null ? void 0 : _c({
532
- eventType: data.type || "custom",
533
- level: data.level,
534
- courseId: data.courseId
535
- });
536
- }
537
- api.logEvent("logGradingStandard", data);
538
- };
539
-
540
- // src/lib/firebase/firebase-analytics/assignment.ts
541
- var logOpenAssignment = (data = {}) => {
542
- api.logEvent("open_assignment", data);
543
- };
544
- var logOpenActivityPreview = (data = {}) => {
545
- api.logEvent("open_activity_preview", data);
546
- };
547
- var logSubmitAssignment = (data = {}) => {
548
- var _a, _b, _c;
549
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "handleCouresAnalyticsEvent")) == null ? void 0 : _c({
550
- eventType: ANALYTICS_EVENT_TYPES.SUBMISSION,
551
- ...data
552
- });
553
- api.logEvent(ANALYTICS_EVENT_TYPES.SUBMISSION, data);
554
- };
555
- var logCreateAssignment = (data = {}) => {
556
- var _a, _b, _c;
557
- if (data.courseId) {
558
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "handleCouresAnalyticsEvent")) == null ? void 0 : _c({
559
- eventType: ANALYTICS_EVENT_TYPES.CREATE_ASSIGNMENT,
560
- ...data
561
- });
562
- }
563
- api.logEvent(ANALYTICS_EVENT_TYPES.CREATE_ASSIGNMENT, data);
564
- };
565
- var logStartAssignment = (data = {}) => {
566
- var _a, _b, _c;
567
- if (data.courseId) {
568
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "handleCouresAnalyticsEvent")) == null ? void 0 : _c({
569
- eventType: ANALYTICS_EVENT_TYPES.ASSIGNMENT_STARTED,
570
- ...data
571
- });
572
- }
573
- api.logEvent(ANALYTICS_EVENT_TYPES.ASSIGNMENT_STARTED, data);
574
- };
575
-
576
- // src/lib/firebase/firebase-analytics/page-analytics.ts
577
- var HANDLE_COURSE_ANALYTICS_EVENT = "handleCouresAnalyticsEvent";
578
- var logRepeatSuccess = (data = {}) => {
579
- var _a, _b, _c;
580
- if (data.courseId) {
581
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, HANDLE_COURSE_ANALYTICS_EVENT)) == null ? void 0 : _c({
582
- eventType: ANALYTICS_EVENT_TYPES.VOICE_SUCCESS,
583
- ...data,
584
- courseId: data.courseId
585
- });
586
- }
587
- api.logEvent(ANALYTICS_EVENT_TYPES.VOICE_SUCCESS, data);
588
- };
589
- var logRepeatFail = (data = {}) => {
590
- var _a, _b, _c;
591
- if (data.courseId) {
592
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, HANDLE_COURSE_ANALYTICS_EVENT)) == null ? void 0 : _c({
593
- eventType: ANALYTICS_EVENT_TYPES.VOICE_FAIL,
594
- ...data,
595
- courseId: data.courseId
596
- });
597
- }
598
- api.logEvent(ANALYTICS_EVENT_TYPES.VOICE_FAIL, data);
599
- };
600
- var logRespondSuccess = (data) => {
601
- var _a, _b, _c;
602
- if (data.courseId) {
603
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, HANDLE_COURSE_ANALYTICS_EVENT)) == null ? void 0 : _c({
604
- eventType: ANALYTICS_EVENT_TYPES.RESPOND_CARD_SUCCESS,
605
- ...data,
606
- courseId: data.courseId
607
- });
608
- }
609
- api.logEvent(ANALYTICS_EVENT_TYPES.RESPOND_CARD_SUCCESS, data);
610
- };
611
- var logRespondFail = (data) => {
612
- var _a, _b, _c;
613
- if (data.courseId) {
614
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, HANDLE_COURSE_ANALYTICS_EVENT)) == null ? void 0 : _c({
615
- eventType: ANALYTICS_EVENT_TYPES.RESPOND_CARD_FAIL,
616
- ...data,
617
- courseId: data.courseId
618
- });
619
- }
620
- api.logEvent(ANALYTICS_EVENT_TYPES.RESPOND_CARD_FAIL, data);
621
- };
622
- var logRespondSubmitted = (data) => {
623
- api.logEvent(ANALYTICS_EVENT_TYPES.RESPOND_CARD_SUBMITTED, data);
624
- };
625
- var logRespondError = (errorDetails) => {
626
- api.logEvent(ANALYTICS_EVENT_TYPES.RESPOND_CARD_ERROR, {
627
- errorDetails
628
- });
629
- };
630
- var logWrittenResponseSuccess = (data) => {
631
- var _a, _b, _c;
632
- if (data.courseId) {
633
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, HANDLE_COURSE_ANALYTICS_EVENT)) == null ? void 0 : _c({
634
- eventType: ANALYTICS_EVENT_TYPES.RESPOND_WRITE_CARD_SUCCESS,
635
- ...data,
636
- courseId: data.courseId
637
- });
638
- }
639
- api.logEvent(ANALYTICS_EVENT_TYPES.RESPOND_WRITE_CARD_SUCCESS, data);
640
- };
641
- var logWrittenResponseFail = (data) => {
642
- var _a, _b, _c;
643
- if (data.courseId) {
644
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, HANDLE_COURSE_ANALYTICS_EVENT)) == null ? void 0 : _c({
645
- eventType: ANALYTICS_EVENT_TYPES.RESPOND_WRITE_CARD_FAIL,
646
- ...data,
647
- courseId: data.courseId
648
- });
649
- }
650
- api.logEvent(ANALYTICS_EVENT_TYPES.RESPOND_WRITE_CARD_FAIL, data);
651
- };
652
- var logWrittenResponseSubmitted = (data = {}) => {
653
- api.logEvent(ANALYTICS_EVENT_TYPES.RESPOND_WRITE_CARD_SUBMITTED, data);
654
- };
655
- var logWrittenResponseError = (errorDetails) => {
656
- api.logEvent(ANALYTICS_EVENT_TYPES.RESPOND_WRITE_CARD_ERROR, {
657
- errorDetails
658
- });
659
- };
660
- var logFreePlanRespond = (data) => {
661
- var _a, _b, _c;
662
- if (data.courseId) {
663
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, HANDLE_COURSE_ANALYTICS_EVENT)) == null ? void 0 : _c({
664
- eventType: ANALYTICS_EVENT_TYPES.RESPOND_FREE_PLAN,
665
- ...data,
666
- courseId: data.courseId
667
- });
668
- }
669
- api.logEvent(ANALYTICS_EVENT_TYPES.RESPOND_FREE_PLAN, data);
670
- };
671
- var logFreePlanWrittenResponse = (data) => {
672
- var _a, _b, _c;
673
- if (data.courseId) {
674
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, HANDLE_COURSE_ANALYTICS_EVENT)) == null ? void 0 : _c({
675
- eventType: ANALYTICS_EVENT_TYPES.RESPOND_WRITE_FREE_PLAN,
676
- ...data,
677
- courseId: data.courseId
678
- });
679
- }
680
- api.logEvent(ANALYTICS_EVENT_TYPES.RESPOND_WRITE_FREE_PLAN, data);
681
- };
682
- var logMultipleChoiceSuccess = (data) => {
683
- var _a, _b, _c;
684
- if (data.courseId) {
685
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, HANDLE_COURSE_ANALYTICS_EVENT)) == null ? void 0 : _c({
686
- eventType: ANALYTICS_EVENT_TYPES.MC_SUCCESS,
687
- courseId: data.courseId
688
- });
689
- }
690
- api.logEvent(ANALYTICS_EVENT_TYPES.MC_SUCCESS, data);
691
- };
692
- var logMultipleChoiceFail = (data) => {
693
- var _a, _b, _c;
694
- if (data.courseId) {
695
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, HANDLE_COURSE_ANALYTICS_EVENT)) == null ? void 0 : _c({
696
- eventType: ANALYTICS_EVENT_TYPES.MC_FAIL,
697
- courseId: data.courseId
698
- });
699
- }
700
- api.logEvent(ANALYTICS_EVENT_TYPES.MC_FAIL, data);
701
- };
702
- var logMultipleChoiceError = (errorDetails) => {
703
- api.logEvent(ANALYTICS_EVENT_TYPES.MC_ERROR, {
704
- errorDetails
705
- });
706
- };
707
-
708
- // src/domains/notification/services/create-notification.service.ts
709
- import dayjs from "dayjs";
710
-
711
- // src/domains/notification/notification.constants.ts
712
- var SPEAKABLE_NOTIFICATIONS = {
713
- NEW_ASSIGNMENT: "new_assignment",
714
- ASSESSMENT_SUBMITTED: "assessment_submitted",
715
- ASSESSMENT_SCORED: "assessment_scored",
716
- NEW_COMMENT: "NEW_COMMENT"
717
- };
718
- var SpeakableNotificationTypes = {
719
- NEW_ASSIGNMENT: "NEW_ASSIGNMENT",
720
- FEEDBACK_FROM_TEACHER: "FEEDBACK_FROM_TEACHER",
721
- MESSAGE_FROM_STUDENT: "MESSAGE_FROM_STUDENT",
722
- PHRASE_MARKED_CORRECT: "PHRASE_MARKED_CORRECT",
723
- STUDENT_PROGRESS: "STUDENT_PROGRESS",
724
- PLAYLIST_FOLLOWERS: "PLAYLIST_FOLLOWERS",
725
- PLAYLIST_PLAYS: "PLAYLIST_PLAYS",
726
- // New notifications
727
- ASSESSMENT_SUBMITTED: "ASSESSMENT_SUBMITTED",
728
- // Notification FOR TEACHER when student submits assessment
729
- ASSESSMENT_SCORED: "ASSESSMENT_SCORED",
730
- // Notification FOR STUDENT when teacher scores assessment
731
- // Comment
732
- NEW_COMMENT: "NEW_COMMENT"
733
- };
734
-
735
- // src/utils/error-handler.ts
736
- var ServiceError = class extends Error {
737
- constructor(message, originalError, code) {
738
- super(message);
739
- this.originalError = originalError;
740
- this.code = code;
741
- this.name = "ServiceError";
742
- }
743
- };
744
- function withErrorHandler(fn, serviceName) {
745
- return async (...args) => {
746
- try {
747
- return await fn(...args);
748
- } catch (error) {
749
- if (error instanceof Error && "code" in error) {
750
- const firebaseError = error;
751
- throw new ServiceError(
752
- `Error in ${serviceName}: ${firebaseError.message}`,
753
- error,
754
- firebaseError.code
755
- );
756
- }
757
- if (error instanceof Error) {
758
- throw new ServiceError(`Error in ${serviceName}: ${error.message}`, error);
759
- }
760
- throw new ServiceError(`Unknown error in ${serviceName}`, error);
761
- }
762
- };
763
- }
764
-
765
- // src/domains/notification/services/send-notification.service.ts
766
- var _sendNotification = async (sendTo, notification) => {
767
- var _a, _b, _c;
768
- const results = await ((_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "createNotificationV2")) == null ? void 0 : _c({
769
- sendTo,
770
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
771
- notification
772
- }));
773
- return results;
774
- };
775
- var sendNotification = withErrorHandler(_sendNotification, "sendNotification");
776
-
777
- // src/domains/notification/services/create-notification.service.ts
778
- var createNotification = async ({
779
- data,
780
- type,
781
- userId,
782
- profile
783
- }) => {
784
- let result;
785
- switch (type) {
786
- case SPEAKABLE_NOTIFICATIONS.NEW_ASSIGNMENT:
787
- result = await handleAssignNotifPromise({ data, profile });
788
- break;
789
- case SPEAKABLE_NOTIFICATIONS.ASSESSMENT_SUBMITTED:
790
- result = await createAssessmentSubmissionNotification({
791
- data,
792
- profile,
793
- userId
794
- });
795
- break;
796
- case SPEAKABLE_NOTIFICATIONS.ASSESSMENT_SCORED:
797
- result = await createAssessmentScoredNotification({
798
- data,
799
- profile
800
- });
801
- break;
802
- default:
803
- result = null;
804
- break;
805
- }
806
- return result;
807
- };
808
- var handleAssignNotifPromise = async ({
809
- data: assignments,
810
- profile
811
- }) => {
812
- if (!assignments.length) return;
813
- try {
814
- const notifsPromises = assignments.map(async (assignment) => {
815
- const {
816
- section,
817
- section: { members },
818
- ...rest
819
- } = assignment;
820
- if (!section || !members) throw new Error("Invalid assignment data");
821
- const data = { section, sendTo: members, assignment: { ...rest } };
822
- return createNewAssignmentNotification({ data, profile });
823
- });
824
- await Promise.all(notifsPromises);
825
- return {
826
- success: true,
827
- message: "Assignment notifications sent successfully"
828
- };
829
- } catch (error) {
830
- console.error("Error in handleAssignNotifPromise:", error);
831
- throw error;
832
- }
833
- };
834
- var createNewAssignmentNotification = async ({
835
- data,
836
- profile
837
- }) => {
838
- var _a;
839
- const { assignment, sendTo } = data;
840
- const teacherName = profile.displayName || "Your teacher";
841
- const dueDate = assignment.dueDateTimestamp ? dayjs(assignment.dueDateTimestamp.toDate()).format("MMM Do") : null;
842
- const results = await sendNotification(sendTo, {
843
- courseId: assignment.courseId,
844
- type: SPEAKABLE_NOTIFICATIONS.NEW_ASSIGNMENT,
845
- senderName: teacherName,
846
- link: `${WEB_BASE_URL}/assignment/${assignment.id}`,
847
- messagePreview: `A new assignment "${assignment.name}" is now available. ${dueDate ? `Due ${dueDate}` : ""}`,
848
- title: "New Assignment Available!",
849
- imageUrl: (_a = profile.image) == null ? void 0 : _a.url
850
- });
851
- return results;
852
- };
853
- var createAssessmentSubmissionNotification = async ({
854
- data: assignment,
855
- profile,
856
- userId
857
- }) => {
858
- var _a;
859
- const studentName = profile.displayName || "Your student";
860
- const results = await sendNotification(assignment.owners, {
861
- courseId: assignment.courseId,
862
- type: SPEAKABLE_NOTIFICATIONS.ASSESSMENT_SUBMITTED,
863
- link: `${WEB_BASE_URL}/a/${assignment.id}?studentId=${userId}`,
864
- title: `Assessment Submitted!`,
865
- senderName: studentName,
866
- messagePreview: `${studentName} has submitted the assessment "${assignment.name}"`,
867
- imageUrl: (_a = profile.image) == null ? void 0 : _a.url
868
- });
869
- return results;
870
- };
871
- var createAssessmentScoredNotification = async ({
872
- data,
873
- profile
874
- }) => {
875
- var _a, _b, _c, _d, _e;
876
- const { assignment, sendTo } = data;
877
- const teacherName = profile.displayName || "Your teacher";
878
- const title = `${assignment.isAssessment ? "Assessment" : "Assignment"} Reviewed!`;
879
- const messagePreview = `Your ${assignment.isAssessment ? "assessment" : "assignment"} has been reviewed by your teacher. Click to view the feedback.`;
880
- const results = await sendNotification(sendTo, {
881
- courseId: assignment.courseId,
882
- type: SPEAKABLE_NOTIFICATIONS.ASSESSMENT_SCORED,
883
- link: `${WEB_BASE_URL}/assignment/${assignment.id}`,
884
- title,
885
- messagePreview,
886
- imageUrl: (_a = profile.image) == null ? void 0 : _a.url,
887
- senderName: teacherName
888
- });
889
- await ((_e = (_c = (_b = api).httpsCallable) == null ? void 0 : _c.call(_b, "sendAssessmentScoredEmail")) == null ? void 0 : _e({
890
- assessmentTitle: assignment.name,
891
- link: `${WEB_BASE_URL}/assignment/${assignment.id}`,
892
- senderImage: ((_d = profile.image) == null ? void 0 : _d.url) || "",
893
- studentId: sendTo[0],
894
- teacherName: profile.displayName
895
- }));
896
- return results;
897
- };
898
-
899
- // src/domains/notification/hooks/notification.hooks.ts
900
- var notificationQueryKeys = {
901
- all: ["notifications"],
902
- byId: (id) => [...notificationQueryKeys.all, id]
903
- };
904
- var useCreateNotification = () => {
905
- const { user, queryClient } = useSpeakableApi();
906
- const handleCreateNotifications = async (type, data) => {
907
- var _a, _b;
908
- const result = await createNotification({
909
- type,
910
- userId: user.auth.uid,
911
- profile: (_a = user == null ? void 0 : user.profile) != null ? _a : {},
912
- data
913
- });
914
- queryClient.invalidateQueries({
915
- queryKey: notificationQueryKeys.byId((_b = user == null ? void 0 : user.auth.uid) != null ? _b : "")
916
- });
917
- return result;
918
- };
919
- return {
920
- createNotification: handleCreateNotifications
921
- };
922
- };
923
-
924
- // src/domains/assignment/assignment.constants.ts
925
- var ASSIGNMENT_ANALYTICS_TYPES = [
926
- "macro" /* Macro */,
927
- "gradebook" /* Gradebook */,
928
- "cards" /* Cards */,
929
- "student" /* Student */,
930
- "student_summary" /* StudentSummary */
931
- ];
932
- var ASSIGNMENTS_COLLECTION = "assignments";
933
- var ANALYTICS_SUBCOLLECTION = "analytics";
934
- var SCORES_SUBCOLLECTION = "scores";
935
- var refsAssignmentFiresotre = {
936
- allAssignments: () => ASSIGNMENTS_COLLECTION,
937
- assignment: (params) => `${ASSIGNMENTS_COLLECTION}/${params.id}`,
938
- assignmentAllAnalytics: (params) => `${ASSIGNMENTS_COLLECTION}/${params.id}/${ANALYTICS_SUBCOLLECTION}`,
939
- assignmentAnalytics: (params) => `${ASSIGNMENTS_COLLECTION}/${params.id}/${ANALYTICS_SUBCOLLECTION}/${params.type}`,
940
- assignmentScores: (params) => `${ASSIGNMENTS_COLLECTION}/${params.id}/${SCORES_SUBCOLLECTION}/${params.userId}`
941
- };
942
-
943
- // src/domains/assignment/utils/create-default-score.ts
944
- var defaultScore = (props) => {
945
- const { serverTimestamp: serverTimestamp3 } = api.accessHelpers();
946
- const score = {
947
- progress: 0,
948
- score: 0,
949
- startDate: serverTimestamp3(),
950
- status: "IN_PROGRESS",
951
- submitted: false,
952
- cards: {},
953
- lastPlayed: serverTimestamp3(),
954
- owners: props.owners,
955
- userId: props.userId
956
- };
957
- if (props.googleClassroomUserId) {
958
- score.googleClassroomUserId = props.googleClassroomUserId;
959
- }
960
- if (props.courseId) {
961
- score.courseId = props.courseId;
962
- }
963
- return score;
964
- };
965
-
966
- // src/domains/assignment/score-practice.constants.ts
967
- var SCORES_PRACTICE_COLLECTION = "users";
968
- var SCORES_PRACTICE_SUBCOLLECTION = "practice";
969
- var refsScoresPractice = {
970
- practiceScores: (params) => `${SCORES_PRACTICE_COLLECTION}/${params.userId}/${SCORES_PRACTICE_SUBCOLLECTION}/${params.setId}`,
971
- practiceScoreHistoryRefDoc: (params) => `${SCORES_PRACTICE_COLLECTION}/${params.userId}/${SCORES_PRACTICE_SUBCOLLECTION}/${params.setId}/attempts/${params.date}`
972
- };
973
-
974
- // src/domains/assignment/services/create-score.service.ts
975
- async function _createScore(params) {
976
- var _a, _b, _c;
977
- if (params.isAssignment) {
978
- const ref = refsAssignmentFiresotre.assignmentScores({
979
- id: params.activityId,
980
- userId: params.userId
981
- });
982
- await ((_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "updateAssignmentGradebookStatus")) == null ? void 0 : _c({
983
- assignmentId: params.activityId,
984
- userId: params.userId,
985
- status: "IN_PROGRESS",
986
- score: null
987
- }));
988
- await api.setDoc(ref, params.scoreData, { merge: true });
989
- return {
990
- id: params.userId
991
- };
992
- } else {
993
- const ref = refsScoresPractice.practiceScores({
994
- userId: params.userId,
995
- setId: params.activityId
996
- });
997
- await api.setDoc(ref, params.scoreData);
998
- return {
999
- id: params.userId
1000
- };
1001
- }
1002
- }
1003
- var createScore = withErrorHandler(_createScore, "createScore");
1004
-
1005
- // src/domains/assignment/services/get-score.service.ts
1006
- async function getAssignmentScore({
1007
- userId,
1008
- assignment,
1009
- googleClassroomUserId
1010
- }) {
1011
- const path = refsAssignmentFiresotre.assignmentScores({
1012
- id: assignment.id,
1013
- userId
1014
- });
1015
- const response = await api.getDoc(path);
1016
- if (response.data == null) {
1017
- const newScore = {
1018
- ...defaultScore({
1019
- owners: [userId],
1020
- userId,
1021
- courseId: assignment.courseId,
1022
- googleClassroomUserId
1023
- }),
1024
- assignmentId: assignment.id
1025
- };
1026
- logStartAssignment({
1027
- courseId: assignment.courseId
1028
- });
1029
- const result = await createScore({
1030
- activityId: assignment.id,
1031
- userId,
1032
- isAssignment: true,
1033
- scoreData: newScore
1034
- });
1035
- return {
1036
- ...newScore,
1037
- id: result.id
1038
- };
1039
- }
1040
- return response.data;
1041
- }
1042
- async function getPracticeScore({ userId, setId }) {
1043
- const path = refsScoresPractice.practiceScores({ userId, setId });
1044
- const response = await api.getDoc(path);
1045
- if (response.data == null) {
1046
- const newScore = {
1047
- ...defaultScore({
1048
- owners: [userId],
1049
- userId
1050
- }),
1051
- setId
1052
- };
1053
- const result = await createScore({
1054
- activityId: setId,
1055
- userId,
1056
- isAssignment: false,
1057
- scoreData: newScore
1058
- });
1059
- return {
1060
- ...newScore,
1061
- id: result.id
1062
- };
1063
- }
1064
- return response.data;
1065
- }
1066
- async function _getScore(params) {
1067
- if (params.isAssignment) {
1068
- return await getAssignmentScore({
1069
- userId: params.userId,
1070
- assignment: {
1071
- id: params.activityId,
1072
- courseId: params.courseId
1073
- },
1074
- googleClassroomUserId: params.googleClassroomUserId
1075
- });
1076
- } else {
1077
- return await getPracticeScore({
1078
- userId: params.userId,
1079
- setId: params.activityId
1080
- });
1081
- }
1082
- }
1083
- var getScore = withErrorHandler(_getScore, "getScore");
1084
-
1085
- // src/domains/assignment/utils/calculateScoreAndProgress.ts
1086
- var calculateScoreAndProgress = (scores, cardsList, weights) => {
1087
- const totalSetPoints = cardsList.reduce((acc, cardId) => {
1088
- acc += (weights == null ? void 0 : weights[cardId]) || 1;
1089
- return acc;
1090
- }, 0);
1091
- const totalPointsAwarded = Object.keys((scores == null ? void 0 : scores.cards) || {}).reduce((acc, cardId) => {
1092
- var _a, _b;
1093
- const cardScores = (_a = scores == null ? void 0 : scores.cards) == null ? void 0 : _a[cardId];
1094
- if ((cardScores == null ? void 0 : cardScores.completed) || (cardScores == null ? void 0 : cardScores.score) || (cardScores == null ? void 0 : cardScores.score) === 0) {
1095
- 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;
1096
- const weight = (weights == null ? void 0 : weights[cardId]) || 1;
1097
- const fraction = (score2 != null ? score2 : 0) / 100;
1098
- if (score2 || score2 === 0) {
1099
- acc += weight * fraction;
1100
- } else {
1101
- acc += weight;
1102
- }
1103
- }
1104
- return acc;
1105
- }, 0);
1106
- const totalCompletedCards = Object.keys((scores == null ? void 0 : scores.cards) || {}).reduce((acc, cardId) => {
1107
- var _a;
1108
- const cardScores = (_a = scores == null ? void 0 : scores.cards) == null ? void 0 : _a[cardId];
1109
- if ((cardScores == null ? void 0 : cardScores.completed) || (cardScores == null ? void 0 : cardScores.score) || (cardScores == null ? void 0 : cardScores.score) === 0) {
1110
- acc += 1;
1111
- }
1112
- return acc;
1113
- }, 0);
1114
- const percent = totalPointsAwarded / totalSetPoints;
1115
- const score = Math.round(percent * 100);
1116
- const progress = Math.round(totalCompletedCards / (cardsList.length || 1) * 100);
1117
- return { score, progress };
1118
- };
1119
- var calculateScoreAndProgress_default = calculateScoreAndProgress;
1120
-
1121
- // src/domains/assignment/services/update-score.service.ts
1122
- async function _updateScore(params) {
1123
- const path = params.isAssignment ? refsAssignmentFiresotre.assignmentScores({
1124
- id: params.activityId,
1125
- userId: params.userId
1126
- }) : refsScoresPractice.practiceScores({
1127
- setId: params.activityId,
1128
- userId: params.userId
1129
- });
1130
- await api.updateDoc(path, {
1131
- ...params.data
1132
- });
1133
- }
1134
- var updateScore = withErrorHandler(_updateScore, "updateScore");
1135
- async function _updateCardScore(params) {
1136
- const path = params.isAssignment ? refsAssignmentFiresotre.assignmentScores({
1137
- id: params.activityId,
1138
- userId: params.userId
1139
- }) : refsScoresPractice.practiceScores({
1140
- setId: params.activityId,
1141
- userId: params.userId
1142
- });
1143
- const updates = Object.keys(params.updates.cardScore).reduce(
1144
- (acc, key) => {
1145
- acc[`cards.${params.cardId}.${key}`] = params.updates.cardScore[key];
1146
- return acc;
1147
- },
1148
- {}
1149
- );
1150
- if (params.updates.progress) {
1151
- updates.progress = params.updates.progress;
1152
- }
1153
- if (params.updates.score) {
1154
- updates.score = params.updates.score;
1155
- }
1156
- await api.updateDoc(path, {
1157
- ...updates
1158
- });
1159
- }
1160
- var updateCardScore = withErrorHandler(_updateCardScore, "updateCardScore");
1161
-
1162
- // src/domains/assignment/services/clear-score.service.ts
1163
- import dayjs2 from "dayjs";
1164
- async function clearScore(params) {
1165
- var _a, _b, _c, _d, _e;
1166
- const update = {
1167
- [`cards.${params.cardId}`]: {
1168
- attempts: ((_a = params.cardScores.attempts) != null ? _a : 1) + 1,
1169
- correct: (_b = params.cardScores.correct) != null ? _b : 0,
1170
- // save old score history
1171
- history: [
1172
- {
1173
- ...params.cardScores,
1174
- attempts: (_c = params.cardScores.attempts) != null ? _c : 1,
1175
- correct: (_d = params.cardScores.correct) != null ? _d : 0,
1176
- retryTime: dayjs2().format("YYYY-MM-DD HH:mm:ss"),
1177
- history: null
1178
- },
1179
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
1180
- ...(_e = params.cardScores.history) != null ? _e : []
1181
- ]
1182
- }
1183
- };
1184
- const path = params.isAssignment ? refsAssignmentFiresotre.assignmentScores({
1185
- id: params.activityId,
1186
- userId: params.userId
1187
- }) : refsScoresPractice.practiceScores({
1188
- setId: params.activityId,
1189
- userId: params.userId
1190
- });
1191
- await api.updateDoc(path, update);
1192
- return {
1193
- update,
1194
- activityId: params.activityId
1195
- };
1196
- }
1197
-
1198
- // src/domains/assignment/services/submit-assignment-score.service.ts
1199
- import dayjs3 from "dayjs";
1200
- async function _submitAssignmentScore({
1201
- cardIds,
1202
- assignment,
1203
- weights,
1204
- userId,
1205
- status,
1206
- studentName
1207
- }) {
1208
- const { serverTimestamp: serverTimestamp3 } = api.accessHelpers();
1209
- const path = refsAssignmentFiresotre.assignmentScores({ id: assignment.id, userId });
1210
- const fieldsUpdated = {
1211
- submitted: true,
1212
- progress: 100,
1213
- submissionDate: serverTimestamp3(),
1214
- status
1215
- };
1216
- if (assignment.isAssessment) {
1217
- const result = await handleAssessment(
1218
- assignment,
1219
- userId,
1220
- cardIds,
1221
- weights,
1222
- fieldsUpdated,
1223
- studentName
1224
- );
1225
- return result;
1226
- } else if (assignment.courseId) {
1227
- await handleCourseAssignment(assignment, userId);
1228
- }
1229
- await api.updateDoc(path, { ...fieldsUpdated });
1230
- return { success: true, fieldsUpdated };
1231
- }
1232
- var submitAssignmentScore = withErrorHandler(
1233
- _submitAssignmentScore,
1234
- "submitAssignmentScore"
1235
- );
1236
- async function handleAssessment(assignment, userId, cardIds, weights, fieldsUpdated, studentName) {
1237
- var _a, _b, _c;
1238
- const path = refsAssignmentFiresotre.assignmentScores({ id: assignment.id, userId });
1239
- const response = await api.getDoc(path);
1240
- if (!response.data) {
1241
- throw new Error("Score not found");
1242
- }
1243
- const { score: scoreCalculated } = calculateScoreAndProgress_default(response.data, cardIds, weights);
1244
- await api.updateDoc(path, { score: scoreCalculated, status: "PENDING_REVIEW" });
1245
- await ((_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "submitAssessment")) == null ? void 0 : _c({
1246
- assignmentId: assignment.id,
1247
- assignmentTitle: assignment.name,
1248
- userId,
1249
- teacherId: assignment.owners[0],
1250
- studentName
1251
- }));
1252
- fieldsUpdated.status = "PENDING_REVIEW";
1253
- return { success: true, fieldsUpdated };
1254
- }
1255
- async function handleCourseAssignment(assignment, userId) {
1256
- var _a, _b, _c;
1257
- await ((_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "submitAssignmentV2")) == null ? void 0 : _c({
1258
- assignmentId: assignment.id,
1259
- userId
1260
- }));
1261
- }
1262
- async function submitPracticeScore({
1263
- setId,
1264
- userId,
1265
- scores
1266
- }) {
1267
- const { serverTimestamp: serverTimestamp3 } = api.accessHelpers();
1268
- const date = dayjs3().format("YYYY-MM-DD-HH-mm");
1269
- const ref = refsScoresPractice.practiceScoreHistoryRefDoc({ setId, userId, date });
1270
- const fieldsUpdated = {
1271
- ...scores,
1272
- submitted: true,
1273
- progress: 100,
1274
- submissionDate: serverTimestamp3(),
1275
- status: "SUBMITTED"
1276
- };
1277
- await api.setDoc(ref, { ...fieldsUpdated });
1278
- const refScores = refsScoresPractice.practiceScores({ userId, setId });
1279
- await api.deleteDoc(refScores);
1280
- return { success: true, fieldsUpdated };
1281
- }
1282
-
1283
- // src/domains/assignment/hooks/score-hooks.ts
1284
- var scoreQueryKeys = {
1285
- all: ["scores"],
1286
- byId: (id) => [...scoreQueryKeys.all, id],
1287
- list: () => [...scoreQueryKeys.all, "list"]
1288
- };
1289
- function useScore({
1290
- isAssignment,
1291
- activityId,
1292
- userId = "",
1293
- courseId,
1294
- enabled = true,
1295
- googleClassroomUserId
1296
- }) {
1297
- return useQuery2({
1298
- queryFn: () => getScore({
1299
- userId,
1300
- courseId,
1301
- activityId,
1302
- googleClassroomUserId,
1303
- isAssignment
1304
- }),
1305
- queryKey: scoreQueryKeys.byId(activityId),
1306
- enabled
1307
- });
1308
- }
1309
- var debounceUpdateScore = debounce(updateScore, 1e3);
1310
- function useUpdateScore() {
1311
- const { queryClient } = useSpeakableApi();
1312
- const mutation = useMutation({
1313
- mutationFn: debounceUpdateScore,
1314
- onMutate: (variables) => {
1315
- return handleOptimisticUpdate({
1316
- queryClient,
1317
- queryKey: scoreQueryKeys.byId(variables.activityId),
1318
- newData: variables.data
1319
- });
1320
- },
1321
- onError: (_, variables, context) => {
1322
- if (context == null ? void 0 : context.previousData)
1323
- queryClient.setQueryData(scoreQueryKeys.byId(variables.activityId), context.previousData);
1324
- },
1325
- onSettled: (_, err, variables) => {
1326
- queryClient.invalidateQueries({
1327
- queryKey: scoreQueryKeys.byId(variables.activityId)
1328
- });
1329
- }
1330
- });
1331
- return {
1332
- mutationUpdateScore: mutation
1333
- };
1334
- }
1335
- function useUpdateCardScore({
1336
- isAssignment,
1337
- activityId,
1338
- userId,
1339
- cardIds,
1340
- weights
1341
- }) {
1342
- const { queryClient } = useSpeakableApi();
1343
- const queryKey = scoreQueryKeys.byId(activityId);
1344
- const mutation = useMutation({
1345
- mutationFn: async ({ cardId, cardScore }) => {
1346
- const previousScores = queryClient.getQueryData(queryKey);
1347
- const { progress, score, newScoreUpdated, updatedCardScore } = getScoreUpdated({
1348
- previousScores: previousScores != null ? previousScores : {},
1349
- cardId,
1350
- cardScore,
1351
- cardIds,
1352
- weights
1353
- });
1354
- await updateCardScore({
1355
- userId,
1356
- cardId,
1357
- isAssignment,
1358
- activityId,
1359
- updates: {
1360
- cardScore: updatedCardScore,
1361
- progress,
1362
- score
1363
- }
1364
- });
1365
- return { cardId, scoresUpdated: newScoreUpdated };
1366
- },
1367
- onMutate: ({ cardId, cardScore }) => {
1368
- queryClient.setQueryData(queryKey, (previousScore) => {
1369
- const updates = handleOptimisticScore({
1370
- score: previousScore,
1371
- cardId,
1372
- cardScore,
1373
- cardIds,
1374
- weights
1375
- });
1376
- return {
1377
- ...previousScore,
1378
- ...updates
1379
- };
1380
- });
1381
- },
1382
- // eslint-disable-next-line no-unused-vars
1383
- onError: (error) => {
1384
- console.log(error.message);
1385
- const previousData = queryClient.getQueryData(queryKey);
1386
- if (previousData) {
1387
- queryClient.setQueryData(queryKey, previousData);
1388
- }
1389
- }
1390
- });
1391
- return {
1392
- mutationUpdateCardScore: mutation
1393
- };
1394
- }
1395
- var getScoreUpdated = ({
1396
- cardId,
1397
- cardScore,
1398
- previousScores,
1399
- cardIds,
1400
- weights
1401
- }) => {
1402
- var _a, _b;
1403
- const previousCard = (_a = previousScores.cards) == null ? void 0 : _a[cardId];
1404
- const newCardScore = {
1405
- ...previousCard != null ? previousCard : {},
1406
- ...cardScore
1407
- };
1408
- const newScores = {
1409
- ...previousScores,
1410
- cards: {
1411
- ...(_b = previousScores.cards) != null ? _b : {},
1412
- [cardId]: newCardScore
1413
- }
1414
- };
1415
- const { score, progress } = calculateScoreAndProgress_default(newScores, cardIds, weights);
1416
- return {
1417
- newScoreUpdated: newScores,
1418
- updatedCardScore: cardScore,
1419
- score,
1420
- progress
1421
- };
1422
- };
1423
- var handleOptimisticScore = ({
1424
- score,
1425
- cardId,
1426
- cardScore,
1427
- cardIds,
1428
- weights
1429
- }) => {
1430
- var _a;
1431
- let cards = { ...(_a = score == null ? void 0 : score.cards) != null ? _a : {} };
1432
- cards = {
1433
- ...cards,
1434
- [cardId]: {
1435
- ...cards[cardId],
1436
- ...cardScore
1437
- }
1438
- };
1439
- const { score: scoreValue, progress } = calculateScoreAndProgress_default(
1440
- // @ts-ignore
1441
- {
1442
- ...score != null ? score : {},
1443
- cards
1444
- },
1445
- cardIds,
1446
- weights
1447
- );
1448
- return { cards, score: scoreValue, progress };
1449
- };
1450
- function useClearScore() {
1451
- const { queryClient } = useSpeakableApi();
1452
- const mutation = useMutation({
1453
- mutationFn: clearScore,
1454
- onSettled: (result) => {
1455
- var _a;
1456
- queryClient.invalidateQueries({
1457
- queryKey: scoreQueryKeys.byId((_a = result == null ? void 0 : result.activityId) != null ? _a : "")
1458
- });
1459
- }
1460
- });
1461
- return {
1462
- mutationClearScore: mutation
1463
- };
1464
- }
1465
- function useSubmitAssignmentScore({
1466
- onAssignmentSubmitted,
1467
- studentName
1468
- }) {
1469
- const { queryClient } = useSpeakableApi();
1470
- const { hasGoogleClassroomGradePassback } = usePermissions_default();
1471
- const { submitAssignmentToGoogleClassroom } = useGoogleClassroom();
1472
- const { createNotification: createNotification2 } = useCreateNotification();
1473
- const mutation = useMutation({
1474
- mutationFn: async ({
1475
- assignment,
1476
- userId,
1477
- cardIds,
1478
- weights,
1479
- scores,
1480
- status
1481
- }) => {
1482
- try {
1483
- const scoreUpdated = await submitAssignmentScore({
1484
- assignment,
1485
- userId,
1486
- cardIds,
1487
- weights,
1488
- status,
1489
- studentName
1490
- });
1491
- if (assignment.courseWorkId != null && !assignment.isAssessment && hasGoogleClassroomGradePassback) {
1492
- await submitAssignmentToGoogleClassroom({
1493
- assignment,
1494
- scores
1495
- });
1496
- }
1497
- if (assignment.isAssessment) {
1498
- createNotification2(SpeakableNotificationTypes.ASSESSMENT_SUBMITTED, assignment);
1499
- }
1500
- if (assignment == null ? void 0 : assignment.id) {
1501
- logSubmitAssignment({
1502
- courseId: assignment == null ? void 0 : assignment.courseId
1503
- });
1504
- }
1505
- onAssignmentSubmitted(assignment.id);
1506
- queryClient.setQueryData(scoreQueryKeys.byId(assignment.id), {
1507
- ...scores,
1508
- ...scoreUpdated.fieldsUpdated
1509
- });
1510
- return {
1511
- success: true,
1512
- message: "Score submitted successfully"
1513
- };
1514
- } catch (error) {
1515
- return {
1516
- success: false,
1517
- error
1518
- };
1519
- }
1520
- }
1521
- });
1522
- return {
1523
- submitAssignmentScore: mutation.mutateAsync,
1524
- isLoading: mutation.isPending
1525
- };
1526
- }
1527
- function useSubmitPracticeScore() {
1528
- const { queryClient } = useSpeakableApi();
1529
- const mutation = useMutation({
1530
- mutationFn: async ({
1531
- setId,
1532
- userId,
1533
- scores
1534
- }) => {
1535
- try {
1536
- await submitPracticeScore({
1537
- setId,
1538
- userId,
1539
- scores
1540
- });
1541
- queryClient.invalidateQueries({
1542
- queryKey: scoreQueryKeys.byId(setId)
1543
- });
1544
- return {
1545
- success: true,
1546
- message: "Score submitted successfully"
1547
- };
1548
- } catch (error) {
1549
- return {
1550
- success: false,
1551
- error
1552
- };
1553
- }
1554
- }
1555
- });
1556
- return {
1557
- submitPracticeScore: mutation.mutateAsync,
1558
- isLoading: mutation.isPending
1559
- };
1560
- }
1561
-
1562
- // src/domains/cards/card.hooks.ts
1563
- import { useMutation as useMutation2, useQueries, useQuery as useQuery3 } from "@tanstack/react-query";
1564
- import { useMemo } from "react";
1565
-
1566
- // src/domains/cards/card.constants.ts
1567
- var CARDS_COLLECTION = "flashcards";
1568
- var refsCardsFiresotre = {
1569
- allCards: CARDS_COLLECTION,
1570
- card: (id) => `${CARDS_COLLECTION}/${id}`
1571
- };
1572
-
1573
- // src/domains/cards/services/get-card.service.ts
1574
- async function _getCard(params) {
1575
- const ref = refsCardsFiresotre.card(params.cardId);
1576
- const response = await api.getDoc(ref);
1577
- if (!response.data) return null;
1578
- return response.data;
1579
- }
1580
- var getCard = withErrorHandler(_getCard, "getCard");
1581
-
1582
- // src/domains/cards/services/create-card.service.ts
1583
- import { v4 } from "uuid";
1584
-
1585
- // src/utils/text-utils.ts
1586
- import sha1 from "js-sha1";
1587
- var purify = (word) => {
1588
- 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();
1589
- };
1590
- var cleanString = (words) => {
1591
- const splitWords = words == null ? void 0 : words.split("+");
1592
- if (splitWords && splitWords.length === 1) {
1593
- const newWord = purify(words);
1594
- return newWord;
1595
- } else if (splitWords && splitWords.length > 1) {
1596
- const split = splitWords.map((w) => purify(w));
1597
- return split;
1598
- } else {
1599
- return "";
1600
- }
1601
- };
1602
- var getWordHash = (word, language) => {
1603
- const cleanedWord = cleanString(word);
1604
- const wordHash = sha1(`${language}-${cleanedWord}`);
1605
- console.log("wordHash core library", wordHash);
1606
- return wordHash;
1607
- };
1608
- function getPhraseLength(phrase, input) {
1609
- if (Array.isArray(phrase) && phrase.includes(input)) {
1610
- return phrase[phrase.indexOf(input)].split(" ").length;
1611
- } else {
1612
- return phrase ? phrase.split(" ").length : 0;
1613
- }
1614
- }
1615
-
1616
- // src/domains/cards/services/get-card-verification-status.service.ts
1617
- var charactarLanguages = ["zh", "ja", "ko"];
1618
- var getVerificationStatus = async (target_text, language) => {
1619
- if ((target_text == null ? void 0 : target_text.length) < 3 && !charactarLanguages.includes(language)) {
1620
- return "NOT_RECOMMENDED" /* NOT_RECOMMENDED */;
1621
- }
1622
- const hash = getWordHash(target_text, language);
1623
- const response = await api.getDoc(`checked-pronunciations/${hash}`);
1624
- try {
1625
- if (response.data) {
1626
- return processRecord(response.data);
1627
- } else {
1628
- return "NOT_CHECKED" /* NOT_CHECKED */;
1629
- }
1630
- } catch (e) {
1631
- return "NOT_CHECKED" /* NOT_CHECKED */;
1632
- }
1633
- };
1634
- var processRecord = (data) => {
1635
- const { pronunciations = 0, fails = 0 } = data;
1636
- const attempts = pronunciations + fails;
1637
- const successRate = attempts > 0 ? pronunciations / attempts * 100 : 0;
1638
- let newStatus = null;
1639
- if (attempts < 6) {
1640
- return "NOT_CHECKED" /* NOT_CHECKED */;
1641
- }
1642
- if (successRate > 25) {
1643
- newStatus = "VERIFIED" /* VERIFIED */;
1644
- } else if (successRate > 10) {
1645
- newStatus = "WARNING" /* WARNING */;
1646
- } else if (fails > 20 && successRate < 10 && pronunciations > 1) {
1647
- newStatus = "NOT_RECOMMENDED" /* NOT_RECOMMENDED */;
1648
- } else if (pronunciations === 0 && fails > 20) {
1649
- newStatus = "NOT_WORKING" /* NOT_WORKING */;
1650
- } else {
1651
- newStatus = "NOT_CHECKED" /* NOT_CHECKED */;
1652
- }
1653
- return newStatus;
1654
- };
1655
-
1656
- // src/domains/cards/services/create-card.service.ts
1657
- async function _createCard({ data }) {
1658
- const response = await api.addDoc(refsCardsFiresotre.allCards, data);
1659
- return response;
1660
- }
1661
- var createCard = withErrorHandler(_createCard, "createCard");
1662
- async function _createCards({ cards }) {
1663
- const { writeBatch: writeBatch3, doc: doc3 } = api.accessHelpers();
1664
- const batch = writeBatch3();
1665
- const cardsWithId = [];
1666
- for (const card of cards) {
1667
- const cardId = v4();
1668
- const ref = doc3(refsCardsFiresotre.card(cardId));
1669
- const newCardObject = {
1670
- ...card,
1671
- id: cardId
1672
- };
1673
- if (card.type === "READ_REPEAT" /* READ_REPEAT */ && card.target_text && card.language) {
1674
- const verificationStatus = await getVerificationStatus(card.target_text, card.language);
1675
- newCardObject.verificationStatus = verificationStatus || null;
1676
- }
1677
- cardsWithId.push(newCardObject);
1678
- batch.set(ref, newCardObject);
1679
- }
1680
- await batch.commit();
1681
- return cardsWithId;
1682
- }
1683
- var createCards = withErrorHandler(_createCards, "createCards");
1684
-
1685
- // src/domains/cards/card.hooks.ts
1686
- var cardsQueryKeys = {
1687
- all: ["cards"],
1688
- one: (params) => [...cardsQueryKeys.all, params.cardId]
1689
- };
1690
- function useCards({
1691
- cardIds,
1692
- enabled = true,
1693
- asObject
1694
- }) {
1695
- const queries = useQueries({
1696
- queries: cardIds.map((cardId) => ({
1697
- enabled: enabled && cardIds.length > 0,
1698
- queryKey: cardsQueryKeys.one({
1699
- cardId
1700
- }),
1701
- queryFn: () => getCard({ cardId })
1702
- }))
1703
- });
1704
- const cards = queries.map((query3) => query3.data).filter(Boolean);
1705
- const cardsObject = useMemo(() => {
1706
- if (!asObject) return null;
1707
- return cards.reduce((acc, card) => {
1708
- acc[card.id] = card;
1709
- return acc;
1710
- }, {});
1711
- }, [asObject, cards]);
1712
- return {
1713
- cards,
1714
- cardsObject,
1715
- cardsQueries: queries
1716
- };
1717
- }
1718
- function useCreateCard() {
1719
- const { queryClient } = useSpeakableApi();
1720
- const mutationCreateCard = useMutation2({
1721
- mutationFn: createCard,
1722
- onSuccess: (cardCreated) => {
1723
- queryClient.invalidateQueries({ queryKey: cardsQueryKeys.one({ cardId: cardCreated.id }) });
1724
- }
1725
- });
1726
- return {
1727
- mutationCreateCard
1728
- };
1729
- }
1730
- function useCreateCards() {
1731
- const mutationCreateCards = useMutation2({
1732
- mutationFn: createCards
1733
- });
1734
- return {
1735
- mutationCreateCards
1736
- };
1737
- }
1738
- function getCardFromCache({
1739
- cardId,
1740
- queryClient
1741
- }) {
1742
- return queryClient.getQueryData(cardsQueryKeys.one({ cardId }));
1743
- }
1744
- function updateCardInCache({
1745
- cardId,
1746
- card,
1747
- queryClient
1748
- }) {
1749
- queryClient.setQueryData(cardsQueryKeys.one({ cardId }), card);
1750
- }
1751
- function useGetCard({ cardId, enabled = true }) {
1752
- const query3 = useQuery3({
1753
- queryKey: cardsQueryKeys.one({ cardId }),
1754
- queryFn: () => getCard({ cardId }),
1755
- enabled: enabled && !!cardId
1756
- });
1757
- return query3;
1758
- }
1759
-
1760
- // src/domains/sets/set.hooks.ts
1761
- import { useQuery as useQuery4 } from "@tanstack/react-query";
1762
-
1763
- // src/domains/sets/set.constants.ts
1764
- var SETS_COLLECTION = "sets";
1765
- var refsSetsFirestore = {
1766
- allSets: SETS_COLLECTION,
1767
- set: (id) => `${SETS_COLLECTION}/${id}`
1768
- };
1769
-
1770
- // src/domains/sets/services/get-set.service.ts
1771
- async function _getSet({ setId }) {
1772
- const response = await api.getDoc(refsSetsFirestore.set(setId));
1773
- return response.data;
1774
- }
1775
- var getSet = withErrorHandler(_getSet, "getSet");
1776
-
1777
- // src/domains/sets/set.hooks.ts
1778
- var setsQueryKeys = {
1779
- all: ["sets"],
1780
- one: (params) => [...setsQueryKeys.all, params.setId]
1781
- };
1782
- var useSet = ({ setId, enabled }) => {
1783
- return useQuery4({
1784
- queryKey: setsQueryKeys.one({ setId }),
1785
- queryFn: () => getSet({ setId }),
1786
- enabled: setId !== void 0 && setId !== "" && enabled
1787
- });
1788
- };
1789
- function getSetFromCache({
1790
- setId,
1791
- queryClient
1792
- }) {
1793
- if (!setId) return null;
1794
- return queryClient.getQueryData(setsQueryKeys.one({ setId }));
1795
- }
1796
- function updateSetInCache({
1797
- set,
1798
- queryClient
1799
- }) {
1800
- const { id, ...setData } = set;
1801
- queryClient.setQueryData(setsQueryKeys.one({ setId: id }), setData);
1802
- }
1803
-
1804
- // src/hooks/useActivity.ts
1805
- import { useEffect as useEffect2 } from "react";
1806
-
1807
- // src/services/add-grading-standard.ts
1808
- var addGradingStandardLog = async (gradingStandard, userId) => {
1809
- logGradingStandardLog(gradingStandard);
1810
- const path = `users/${userId}/grading_standard_logs`;
1811
- await api.addDoc(path, gradingStandard);
1812
- };
1813
-
1814
- // src/hooks/useActivityTracker.ts
1815
- import { v4 as v42 } from "uuid";
1816
- function useActivityTracker({ userId }) {
1817
- const trackActivity = async ({
1818
- activityName,
1819
- activityType,
1820
- id = v42(),
1821
- language = ""
1822
- }) => {
1823
- if (userId) {
1824
- const { doc: doc3, serverTimestamp: serverTimestamp3, setDoc: setDoc3 } = api.accessHelpers();
1825
- const activityRef = doc3(`users/${userId}/activity/${id}`);
1826
- const timestamp = serverTimestamp3();
1827
- await setDoc3(activityRef, {
1828
- name: activityName,
1829
- type: activityType,
1830
- lastSeen: timestamp,
1831
- id,
1832
- language
1833
- });
1834
- }
1835
- };
1836
- return {
1837
- trackActivity
1838
- };
1839
- }
1840
-
1841
- // src/hooks/useActivity.ts
1842
- function useActivity({
1843
- id,
1844
- isAssignment,
1845
- onAssignmentSubmitted,
1846
- ltiData
1847
- }) {
1848
- var _a, _b;
1849
- const { queryClient, user } = useSpeakableApi();
1850
- const userId = user.auth.uid;
1851
- const assignmentQuery = useAssignment({
1852
- assignmentId: id,
1853
- userId,
1854
- enabled: isAssignment
1855
- });
1856
- const activeAssignment = assignmentQuery.data;
1857
- const setId = isAssignment ? (_a = activeAssignment == null ? void 0 : activeAssignment.setId) != null ? _a : "" : id;
1858
- const querySet = useSet({ setId });
1859
- const setData = querySet.data;
1860
- const assignmentContent = activeAssignment == null ? void 0 : activeAssignment.content;
1861
- const assignmentWeights = activeAssignment == null ? void 0 : activeAssignment.weights;
1862
- const setContent = setData == null ? void 0 : setData.content;
1863
- const setWeights = setData == null ? void 0 : setData.weights;
1864
- const contentCardsToUse = isAssignment ? assignmentContent != null ? assignmentContent : setContent : setContent;
1865
- const weightsToUse = isAssignment ? assignmentWeights != null ? assignmentWeights : setWeights : setWeights;
1866
- const activityId = isAssignment ? (_b = activeAssignment == null ? void 0 : activeAssignment.id) != null ? _b : "" : setId;
1867
- const { cardsObject, cardsQueries, cards } = useCards({
1868
- cardIds: contentCardsToUse != null ? contentCardsToUse : [],
1869
- enabled: querySet.isSuccess,
1870
- asObject: true
1871
- });
1872
- const scoreQuery = useScore({
1873
- isAssignment,
1874
- activityId: id,
1875
- userId,
1876
- courseId: activeAssignment == null ? void 0 : activeAssignment.courseId,
1877
- googleClassroomUserId: user.profile.googleClassroomUserId,
1878
- enabled: isAssignment ? assignmentQuery.isSuccess : querySet.isSuccess
1879
- });
1880
- const { mutationUpdateScore } = useUpdateScore();
1881
- const { mutationUpdateCardScore } = useUpdateCardScore({
1882
- activityId,
1883
- isAssignment,
1884
- userId,
1885
- cardIds: contentCardsToUse != null ? contentCardsToUse : [],
1886
- weights: weightsToUse != null ? weightsToUse : {}
1887
- });
1888
- const { mutationClearScore } = useClearScore();
1889
- const { submitAssignmentScore: submitAssignmentScore2 } = useSubmitAssignmentScore({
1890
- onAssignmentSubmitted,
1891
- studentName: user.profile.displayName
1892
- });
1893
- const { submitPracticeScore: submitPracticeScore2 } = useSubmitPracticeScore();
1894
- const handleUpdateScore = (data) => {
1895
- mutationUpdateScore.mutate({
1896
- data,
1897
- isAssignment,
1898
- activityId,
1899
- userId
1900
- });
1901
- };
1902
- const handleUpdateCardScore = (cardId, cardScore) => {
1903
- mutationUpdateCardScore.mutate({ cardId, cardScore });
1904
- if (cardScore.proficiency_level) {
1905
- logGradingStandardEntry({
1906
- type: cardScore.proficiency_level.standardId,
1907
- cardId,
1908
- gradingStandard: cardScore.proficiency_level
1909
- });
1910
- } else if (cardScore.wida || cardScore.actfl) {
1911
- logGradingStandardEntry({
1912
- type: cardScore.wida ? "wida" : "actfl",
1913
- cardId,
1914
- gradingStandard: cardScore.wida || cardScore.actfl || { level: "", justification: "" }
1915
- });
1916
- }
1917
- };
1918
- const onClearScore = ({
1919
- cardId,
1920
- wasCompleted = true
1921
- }) => {
1922
- var _a2, _b2;
1923
- const currentCard = cardsObject == null ? void 0 : cardsObject[cardId];
1924
- if ((currentCard == null ? void 0 : currentCard.type) === "MULTIPLE_CHOICE" /* MULTIPLE_CHOICE */ || (currentCard == null ? void 0 : currentCard.type) === "READ_REPEAT" /* READ_REPEAT */) {
1925
- return;
1926
- }
1927
- const queryKeys = scoreQueryKeys.byId(activityId);
1928
- const activeCardScores = (_b2 = (_a2 = queryClient.getQueryData(queryKeys)) == null ? void 0 : _a2.cards) == null ? void 0 : _b2[cardId];
1929
- if (activeCardScores === void 0) return;
1930
- mutationClearScore.mutate({
1931
- isAssignment,
1932
- activityId,
1933
- cardScores: activeCardScores,
1934
- cardId,
1935
- userId
1936
- });
1937
- };
1938
- const onSubmitScore = async () => {
1939
- var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
1940
- try {
1941
- let results;
1942
- if (isAssignment) {
1943
- const cardScores = ((_a2 = scoreQuery.data) == null ? void 0 : _a2.cards) || {};
1944
- const hasPendingReview = Object.values(cardScores).some(
1945
- (cardScore) => cardScore.status === "pending_review"
1946
- );
1947
- results = await submitAssignmentScore2({
1948
- assignment: {
1949
- id: (_c = (_b2 = assignmentQuery.data) == null ? void 0 : _b2.id) != null ? _c : "",
1950
- name: (_e = (_d = assignmentQuery.data) == null ? void 0 : _d.name) != null ? _e : "",
1951
- owners: (_g = (_f = assignmentQuery.data) == null ? void 0 : _f.owners) != null ? _g : [],
1952
- courseId: (_i = (_h = assignmentQuery.data) == null ? void 0 : _h.courseId) != null ? _i : "",
1953
- courseWorkId: (_k = (_j = assignmentQuery.data) == null ? void 0 : _j.courseWorkId) != null ? _k : "",
1954
- isAssessment: (_m = (_l = assignmentQuery.data) == null ? void 0 : _l.isAssessment) != null ? _m : false,
1955
- maxPoints: (_o = (_n = assignmentQuery.data) == null ? void 0 : _n.maxPoints) != null ? _o : 0
1956
- },
1957
- userId,
1958
- cardIds: contentCardsToUse != null ? contentCardsToUse : [],
1959
- scores: scoreQuery.data,
1960
- weights: weightsToUse != null ? weightsToUse : {},
1961
- status: hasPendingReview ? "PENDING_REVIEW" : "FINALIZED"
1962
- });
1963
- if ((_p = assignmentQuery.data) == null ? void 0 : _p.ltiDeeplink) {
1964
- submitLTIScore({
1965
- maxPoints: (_q = assignmentQuery.data) == null ? void 0 : _q.maxPoints,
1966
- score: (_s = (_r = scoreQuery.data) == null ? void 0 : _r.score) != null ? _s : 0,
1967
- SERVICE_KEY: (_t = ltiData == null ? void 0 : ltiData.serviceKey) != null ? _t : "",
1968
- lineItemId: (_u = ltiData == null ? void 0 : ltiData.lineItemId) != null ? _u : "",
1969
- lti_id: (_v = ltiData == null ? void 0 : ltiData.lti_id) != null ? _v : ""
1970
- });
1971
- }
1972
- } else {
1973
- results = await submitPracticeScore2({
1974
- setId: (_x = (_w = querySet.data) == null ? void 0 : _w.id) != null ? _x : "",
1975
- userId,
1976
- scores: scoreQuery.data
1977
- });
1978
- }
1979
- return results;
1980
- } catch (error) {
1981
- return {
1982
- success: false,
1983
- error
1984
- };
1985
- }
1986
- };
1987
- const logGradingStandardEntry = ({
1988
- cardId,
1989
- gradingStandard,
1990
- type
1991
- }) => {
1992
- var _a2, _b2, _c, _d, _e, _f, _g, _h, _i;
1993
- const card = cardsObject == null ? void 0 : cardsObject[cardId];
1994
- const scoresObject = queryClient.getQueryData(scoreQueryKeys.byId(activityId));
1995
- const cardScore = (_a2 = scoresObject == null ? void 0 : scoresObject.cards) == null ? void 0 : _a2[cardId];
1996
- const serverTimestamp3 = api.helpers.serverTimestamp;
1997
- addGradingStandardLog(
1998
- {
1999
- assignmentId: (_b2 = activeAssignment == null ? void 0 : activeAssignment.id) != null ? _b2 : "",
2000
- courseId: (_c = activeAssignment == null ? void 0 : activeAssignment.courseId) != null ? _c : "",
2001
- teacherId: (_d = activeAssignment == null ? void 0 : activeAssignment.owners[0]) != null ? _d : "",
2002
- setId: (_e = setData == null ? void 0 : setData.id) != null ? _e : "",
2003
- cardId,
2004
- level: gradingStandard.level,
2005
- justification: gradingStandard.justification,
2006
- transcript: (_f = cardScore == null ? void 0 : cardScore.transcript) != null ? _f : "",
2007
- audioUrl: (_g = cardScore == null ? void 0 : cardScore.audio) != null ? _g : "",
2008
- prompt: (_h = card == null ? void 0 : card.prompt) != null ? _h : "",
2009
- responseType: (card == null ? void 0 : card.type) === "RESPOND_WRITE" /* RESPOND_WRITE */ ? "written" : "spoken",
2010
- type,
2011
- dateMade: serverTimestamp3(),
2012
- language: (_i = card == null ? void 0 : card.language) != null ? _i : ""
2013
- },
2014
- userId
2015
- );
2016
- };
2017
- useEffect2(() => {
2018
- if (isAssignment) {
2019
- logOpenAssignment({ assignmentId: id });
2020
- } else {
2021
- logOpenActivityPreview({ setId: id });
2022
- }
2023
- }, []);
2024
- useInitActivity({
2025
- assignment: activeAssignment != null ? activeAssignment : void 0,
2026
- set: setData != null ? setData : void 0,
2027
- enabled: !!setData,
2028
- userId
2029
- });
2030
- return {
2031
- set: {
2032
- data: setData,
2033
- query: querySet
2034
- },
2035
- cards: {
2036
- data: cardsObject,
2037
- query: cardsQueries,
2038
- cardsArray: cards
2039
- },
2040
- assignment: {
2041
- data: isAssignment ? activeAssignment : void 0,
2042
- query: assignmentQuery
2043
- },
2044
- scores: {
2045
- data: scoreQuery.data,
2046
- query: scoreQuery,
2047
- actions: {
2048
- update: handleUpdateScore,
2049
- clear: onClearScore,
2050
- submit: onSubmitScore,
2051
- updateCard: handleUpdateCardScore,
2052
- logGradingStandardEntry
2053
- }
2054
- }
2055
- };
2056
- }
2057
- var useInitActivity = ({
2058
- assignment,
2059
- set,
2060
- enabled,
2061
- userId
2062
- }) => {
2063
- const { trackActivity } = useActivityTracker({ userId });
2064
- const init = () => {
2065
- var _a, _b, _c, _d, _e, _f, _g;
2066
- if (!enabled) return;
2067
- if (!assignment) {
2068
- trackActivity({
2069
- activityName: (_a = set == null ? void 0 : set.name) != null ? _a : "",
2070
- activityType: "set",
2071
- id: set == null ? void 0 : set.id,
2072
- language: set == null ? void 0 : set.language
2073
- });
2074
- } else if (assignment.name) {
2075
- trackActivity({
2076
- activityName: assignment.name,
2077
- activityType: assignment.isAssessment ? "assessment" : "assignment",
2078
- id: assignment.id,
2079
- language: set == null ? void 0 : set.language
2080
- });
2081
- }
2082
- if (set == null ? void 0 : set.public) {
2083
- (_d = (_c = (_b = api).httpsCallable) == null ? void 0 : _c.call(_b, "onSetOpened")) == null ? void 0 : _d({
2084
- setId: set.id,
2085
- language: set.language
2086
- });
2087
- }
2088
- (_g = (_f = (_e = api).httpsCallable) == null ? void 0 : _f.call(_e, "updateAlgoliaIndex")) == null ? void 0 : _g({
2089
- updatePlays: true,
2090
- objectID: set == null ? void 0 : set.id
2091
- });
2092
- };
2093
- useEffect2(() => {
2094
- init();
2095
- }, [set]);
2096
- };
2097
- var submitLTIScore = async ({
2098
- maxPoints,
2099
- score,
2100
- SERVICE_KEY,
2101
- lineItemId,
2102
- lti_id
2103
- }) => {
2104
- var _a, _b, _c;
2105
- try {
2106
- if (!SERVICE_KEY || !lineItemId || !lti_id) {
2107
- throw new Error("Missing required LTI credentials");
2108
- }
2109
- const earnedPoints = score ? score / 100 * maxPoints : 0;
2110
- const { data } = await ((_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "submitLTIAssignmentScore")) == null ? void 0 : _c({
2111
- SERVICE_KEY,
2112
- scoreData: {
2113
- lineItemId,
2114
- userId: lti_id,
2115
- maxPoints,
2116
- earnedPoints
2117
- }
2118
- }));
2119
- return { success: true, data };
2120
- } catch (error) {
2121
- console.error("Failed to submit LTI score:", error);
2122
- return {
2123
- success: false,
2124
- error: error instanceof Error ? error : new Error("Unknown error occurred")
2125
- };
2126
- }
2127
- };
2128
-
2129
- // src/hooks/useActivityFeedbackAccess.ts
2130
- import { useQuery as useQuery5 } from "@tanstack/react-query";
2131
- var activityFeedbackAccessQueryKeys = {
2132
- activityFeedbackAccess: (args) => ["activityFeedbackAccess", ...Object.values(args)]
2133
- };
2134
- var useActivityFeedbackAccess = ({
2135
- aiEnabled = false,
2136
- isActivityRoute = false
2137
- }) => {
2138
- var _a, _b, _c;
2139
- const { user } = useSpeakableApi();
2140
- const uid = user.auth.uid;
2141
- const isTeacher = (_a = user.profile) == null ? void 0 : _a.isTeacher;
2142
- const isStudent = (_b = user.profile) == null ? void 0 : _b.isStudent;
2143
- const userRoles = ((_c = user.profile) == null ? void 0 : _c.roles) || [];
2144
- const query3 = useQuery5({
2145
- queryKey: activityFeedbackAccessQueryKeys.activityFeedbackAccess({
2146
- aiEnabled,
2147
- isActivityRoute
2148
- }),
2149
- queryFn: async () => {
2150
- var _a2, _b2, _c2;
2151
- if (!uid) {
2152
- return {
2153
- canAccessFeedback: false,
2154
- reason: "Missing user ID",
2155
- isUnlimited: false,
2156
- accessType: "none"
2157
- };
2158
- }
2159
- try {
2160
- if (aiEnabled) {
2161
- return {
2162
- canAccessFeedback: true,
2163
- reason: "AI feedback enabled",
2164
- isUnlimited: true,
2165
- accessType: "ai_enabled"
2166
- };
2167
- }
2168
- if (isTeacher || userRoles.includes("ADMIN")) {
2169
- return {
2170
- canAccessFeedback: true,
2171
- reason: "Teacher preview access",
2172
- isUnlimited: true,
2173
- accessType: "teacher_preview"
2174
- };
2175
- }
2176
- if (isStudent && isActivityRoute) {
2177
- try {
2178
- const result = await ((_c2 = (_b2 = (_a2 = api).httpsCallable) == null ? void 0 : _b2.call(_a2, "checkStudentTeacherPlan")) == null ? void 0 : _c2({
2179
- studentId: uid
2180
- }));
2181
- const planCheckResult = result.data;
2182
- if (planCheckResult.canAccessFeedback) {
2183
- return {
2184
- canAccessFeedback: true,
2185
- reason: planCheckResult.reason || "Student access via teacher with active plan",
2186
- isUnlimited: planCheckResult.hasTeacherWithUnlimitedAccess,
2187
- accessType: "student_with_teacher_plan"
2188
- };
2189
- } else {
2190
- return {
2191
- canAccessFeedback: false,
2192
- reason: planCheckResult.reason || "No teacher with active plan found",
2193
- isUnlimited: false,
2194
- accessType: "none"
2195
- };
2196
- }
2197
- } catch (error) {
2198
- console.error("Error checking student teacher plan:", error);
2199
- return {
2200
- canAccessFeedback: false,
2201
- reason: "Error checking teacher plans",
2202
- isUnlimited: false,
2203
- accessType: "none"
2204
- };
2205
- }
2206
- }
2207
- return {
2208
- canAccessFeedback: false,
2209
- reason: "No access permissions found for current context",
2210
- isUnlimited: false,
2211
- accessType: "none"
2212
- };
2213
- } catch (error) {
2214
- console.error("Error checking activity feedback access:", error);
2215
- return {
2216
- canAccessFeedback: false,
2217
- reason: "Error checking access permissions",
2218
- isUnlimited: false,
2219
- accessType: "none"
2220
- };
2221
- }
2222
- },
2223
- enabled: !!uid,
2224
- staleTime: 5 * 60 * 1e3,
2225
- // 5 minutes
2226
- gcTime: 10 * 60 * 1e3
2227
- // 10 minutes
2228
- });
2229
- return {
2230
- ...query3
2231
- };
2232
- };
2233
-
2234
- // src/hooks/useCredits.ts
2235
- import { useQuery as useQuery6 } from "@tanstack/react-query";
2236
- var creditQueryKeys = {
2237
- userCredits: (uid) => ["userCredits", uid]
2238
- };
2239
- var useUserCredits = () => {
2240
- const { user } = useSpeakableApi();
2241
- const email = user.auth.email;
2242
- const uid = user.auth.uid;
2243
- const query3 = useQuery6({
2244
- queryKey: creditQueryKeys.userCredits(uid),
2245
- queryFn: () => fetchUserCredits({ uid, email }),
2246
- enabled: !!uid,
2247
- refetchInterval: 1e3 * 60 * 5
2248
- });
2249
- return {
2250
- ...query3
2251
- };
2252
- };
2253
- var fetchUserCredits = async ({ uid, email }) => {
2254
- if (!uid) {
2255
- throw new Error("User ID is required");
2256
- }
2257
- const contractSnap = await api.getDoc(`creditContracts/${uid}`);
2258
- if (contractSnap.data == null) {
2259
- return {
2260
- id: uid,
2261
- userId: uid,
2262
- email,
2263
- effectivePlanId: "free_tier",
2264
- status: "inactive",
2265
- isUnlimited: false,
2266
- creditsAvailable: 100,
2267
- creditsAllocatedThisPeriod: 100,
2268
- topOffCreditsAvailable: 0,
2269
- topOffCreditsTotal: 0,
2270
- allocationSource: "free_tier",
2271
- sourceDetails: {},
2272
- periodStart: null,
2273
- periodEnd: null,
2274
- planTermEndTimestamp: null,
2275
- ownerType: "individual",
2276
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2277
- lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
2278
- };
2279
- }
2280
- const contractData = contractSnap.data;
2281
- const monthlyCredits = (contractData == null ? void 0 : contractData.creditsAvailable) || 0;
2282
- const topOffCredits = (contractData == null ? void 0 : contractData.topOffCreditsAvailable) || 0;
2283
- const totalCredits = monthlyCredits + topOffCredits;
2284
- return {
2285
- id: contractSnap.id,
2286
- ...contractData,
2287
- // Add computed total for convenience
2288
- totalCreditsAvailable: totalCredits
2289
- };
2290
- };
2291
-
2292
- // src/constants/all-langs.json
2293
- var all_langs_default = {
2294
- af: "Afrikaans",
2295
- sq: "Albanian",
2296
- am: "Amharic",
2297
- ar: "Arabic",
2298
- hy: "Armenian",
2299
- az: "Azerbaijani",
2300
- eu: "Basque",
2301
- be: "Belarusian",
2302
- bn: "Bengali",
2303
- bs: "Bosnian",
2304
- bg: "Bulgarian",
2305
- ca: "Catalan",
2306
- ceb: "Cebuano",
2307
- zh: "Chinese",
2308
- co: "Corsican",
2309
- hr: "Croatian",
2310
- cs: "Czech",
2311
- da: "Danish",
2312
- nl: "Dutch",
2313
- en: "English",
2314
- eo: "Esperanto",
2315
- et: "Estonian",
2316
- fi: "Finnish",
2317
- fr: "French",
2318
- fy: "Frisian",
2319
- gl: "Galician",
2320
- ka: "Georgian",
2321
- de: "German",
2322
- el: "Greek",
2323
- gu: "Gujarati",
2324
- ht: "Haitian Creole",
2325
- ha: "Hausa",
2326
- haw: "Hawaiian",
2327
- he: "Hebrew",
2328
- hi: "Hindi",
2329
- hmn: "Hmong",
2330
- hu: "Hungarian",
2331
- is: "Icelandic",
2332
- ig: "Igbo",
2333
- id: "Indonesian",
2334
- ga: "Irish",
2335
- it: "Italian",
2336
- ja: "Japanese",
2337
- jv: "Javanese",
2338
- kn: "Kannada",
2339
- kk: "Kazakh",
2340
- km: "Khmer",
2341
- ko: "Korean",
2342
- ku: "Kurdish",
2343
- ky: "Kyrgyz",
2344
- lo: "Lao",
2345
- la: "Latin",
2346
- lv: "Latvian",
2347
- lt: "Lithuanian",
2348
- lb: "Luxembourgish",
2349
- mk: "Macedonian",
2350
- mg: "Malagasy",
2351
- ms: "Malay",
2352
- ml: "Malayalam",
2353
- mt: "Maltese",
2354
- mi: "Maori",
2355
- mr: "Marathi",
2356
- mn: "Mongolian",
2357
- my: "Myanmar (Burmese)",
2358
- ne: "Nepali",
2359
- no: "Norwegian",
2360
- ny: "Nyanja (Chichewa)",
2361
- ps: "Pashto",
2362
- fa: "Persian",
2363
- pl: "Polish",
2364
- pt: "Portuguese",
2365
- pa: "Punjabi",
2366
- ro: "Romanian",
2367
- ru: "Russian",
2368
- sm: "Samoan",
2369
- gd: "Scots Gaelic",
2370
- sr: "Serbian",
2371
- st: "Sesotho",
2372
- sn: "Shona",
2373
- sd: "Sindhi",
2374
- si: "Sinhala (Sinhalese)",
2375
- sk: "Slovak",
2376
- sl: "Slovenian",
2377
- so: "Somali",
2378
- es: "Spanish",
2379
- su: "Sundanese",
2380
- sw: "Swahili",
2381
- sv: "Swedish",
2382
- tl: "Tagalog (Filipino)",
2383
- tg: "Tajik",
2384
- ta: "Tamil",
2385
- te: "Telugu",
2386
- th: "Thai",
2387
- tr: "Turkish",
2388
- uk: "Ukrainian",
2389
- ur: "Urdu",
2390
- uz: "Uzbek",
2391
- vi: "Vietnamese",
2392
- cy: "Welsh",
2393
- xh: "Xhosa",
2394
- yi: "Yiddish",
2395
- yo: "Yoruba",
2396
- zu: "Zulu"
2397
- };
2398
-
2399
- // src/utils/ai/get-respond-card-tool.ts
2400
- var getRespondCardTool = ({
2401
- language,
2402
- standard = "actfl"
2403
- }) => {
2404
- const lang = all_langs_default[language] || "English";
2405
- const tool = {
2406
- tool_choice: {
2407
- type: "function",
2408
- function: { name: "get_feedback" }
2409
- },
2410
- tools: [
2411
- {
2412
- type: "function",
2413
- function: {
2414
- name: "get_feedback",
2415
- description: "Get feedback on a student's response",
2416
- parameters: {
2417
- type: "object",
2418
- required: [
2419
- "success",
2420
- "score",
2421
- "score_justification",
2422
- "errors",
2423
- "improvedResponse",
2424
- "compliments"
2425
- ],
2426
- properties: {
2427
- success: {
2428
- type: "boolean",
2429
- description: "Mark true if the student's response was on-topic and generally demonstrated understanding. A few grammar mistakes are acceptable. Mark false if the student's response was off-topic or did not demonstrate understanding."
2430
- },
2431
- errors: {
2432
- type: "array",
2433
- items: {
2434
- type: "object",
2435
- required: ["error", "grammar_error_type", "correction", "justification"],
2436
- properties: {
2437
- error: {
2438
- type: "string",
2439
- description: "The grammatical error in the student's response."
2440
- },
2441
- correction: {
2442
- type: "string",
2443
- description: "The suggested correction to the error"
2444
- },
2445
- justification: {
2446
- type: "string",
2447
- description: `An explanation of the rationale behind the suggested correction. WRITE THIS IN ${lang}!`
2448
- },
2449
- grammar_error_type: {
2450
- type: "string",
2451
- enum: [
2452
- "subjVerbAgree",
2453
- "tenseErrors",
2454
- "articleMisuse",
2455
- "prepositionErrors",
2456
- "adjNounAgree",
2457
- "pronounErrors",
2458
- "wordOrder",
2459
- "verbConjugation",
2460
- "pluralization",
2461
- "negationErrors",
2462
- "modalVerbMisuse",
2463
- "relativeClause",
2464
- "auxiliaryVerb",
2465
- "complexSentenceAgreement",
2466
- "idiomaticExpression",
2467
- "registerInconsistency",
2468
- "voiceMisuse"
2469
- ],
2470
- description: "The type of grammatical error found. It should be one of the following categories: subject-verb agreement, tense errors, article misuse, preposition errors, adjective-noun agreement, pronoun errors, word order, verb conjugation, pluralization errors, negation errors, modal verb misuse, relative clause errors, auxiliary verb misuse, complex sentence agreement, idiomatic expression, register inconsistency, or voice misuse"
2471
- }
2472
- }
2473
- },
2474
- description: "An array of objects, each representing a grammatical error in the student's response. Each object should have the following properties: error, grammar_error_type, correction, and justification. If there were no errors, return an empty array."
2475
- },
2476
- compliments: {
2477
- type: "array",
2478
- items: {
2479
- type: "string"
2480
- },
2481
- description: `An array of strings, each representing something the student did well. Each string should be WRITTEN IN ${lang}!`
2482
- },
2483
- improvedResponse: {
2484
- type: "string",
2485
- description: "An improved response with proper grammar and more detail, if applicable."
2486
- },
2487
- score: {
2488
- type: "number",
2489
- description: "A score between 0 and 100, reflecting the overall quality of the response"
2490
- },
2491
- score_justification: {
2492
- type: "string",
2493
- description: "An explanation of the rationale behind the assigned score, considering both accuracy and fluency"
2494
- }
2495
- }
2496
- }
2497
- }
2498
- }
2499
- ]
2500
- };
2501
- if (standard === "wida") {
2502
- const wida_level = {
2503
- type: "number",
2504
- enum: [1, 2, 3, 4, 5, 6],
2505
- description: `The student's WIDA (World-Class Instructional Design and Assessment) proficiency level. Choose one of the following options: 1, 2, 3, 4, 5, 6 which corresponds to
2506
-
2507
- 1 - Entering
2508
- 2 - Emerging
2509
- 3 - Developing
2510
- 4 - Expanding
2511
- 5 - Bridging
2512
- 6 - Reaching
2513
-
2514
- This is an estimate based on the level of the student's response. Use the descriptions of the WIDA speaking standards to guide your decision.
2515
- `
2516
- };
2517
- const wida_justification = {
2518
- type: "string",
2519
- description: `An explanation of the rationale behind the assigned WIDA level of the response, considering both accuracy and fluency. WRITE THIS IN ENGLISH!`
2520
- };
2521
- tool.tools[0].function.parameters.required.push("wida_level");
2522
- tool.tools[0].function.parameters.required.push("wida_justification");
2523
- tool.tools[0].function.parameters.properties.wida_level = wida_level;
2524
- tool.tools[0].function.parameters.properties.wida_justification = wida_justification;
2525
- } else {
2526
- const actfl_level = {
2527
- type: "string",
2528
- enum: ["NL", "NM", "NH", "IL", "IM", "IH", "AL", "AM", "AH", "S", "D"],
2529
- description: "The student's ACTFL (American Council on the Teaching of Foreign Languages) proficiency level. Choose one of the following options: NL, NM, NH, IL, IM, IH, AL, AM, AH, S, or D"
2530
- };
2531
- const actfl_justification = {
2532
- type: "string",
2533
- description: "An explanation of the rationale behind the assigned ACTFL level, considering both accuracy and fluency"
2534
- };
2535
- tool.tools[0].function.parameters.required.push("actfl_level");
2536
- tool.tools[0].function.parameters.required.push("actfl_justification");
2537
- tool.tools[0].function.parameters.properties.actfl_level = actfl_level;
2538
- tool.tools[0].function.parameters.properties.actfl_justification = actfl_justification;
2539
- }
2540
- return tool;
2541
- };
2542
-
2543
- // src/hooks/useOpenAI.ts
2544
- var useBaseOpenAI = ({
2545
- onTranscriptSuccess,
2546
- onTranscriptError,
2547
- onCompletionSuccess,
2548
- onCompletionError,
2549
- aiEnabled,
2550
- submitAudioResponse,
2551
- uploadAudioAndGetTranscript,
2552
- onGetAudioUrlAndTranscript
2553
- }) => {
2554
- const { user, queryClient } = useSpeakableApi();
2555
- const currentUserId = user.auth.uid;
2556
- const { data: feedbackAccess } = useActivityFeedbackAccess({
2557
- aiEnabled
2558
- });
2559
- const getTranscript = async (audioUrl, language) => {
2560
- var _a, _b;
2561
- try {
2562
- const getAssemblyAITranscript = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "transcribeAssemblyAIAudio");
2563
- const response = await (getAssemblyAITranscript == null ? void 0 : getAssemblyAITranscript({
2564
- audioUrl,
2565
- language
2566
- }));
2567
- const transcript = response == null ? void 0 : response.data;
2568
- return transcript;
2569
- } catch (error) {
2570
- console.log("error", error);
2571
- onTranscriptError({
2572
- type: "TRANSCRIPT",
2573
- message: (error == null ? void 0 : error.message) || "Error getting transcript"
2574
- });
2575
- throw new Error(error);
2576
- }
2577
- };
2578
- const getFreeResponseCompletion = async (messages, isFreeResponse, feedbackLanguage, gradingStandard = "actfl") => {
2579
- var _a, _b, _c, _d, _e;
2580
- const responseTool = getRespondCardTool({
2581
- language: feedbackLanguage,
2582
- standard: gradingStandard
2583
- });
2584
- try {
2585
- const createChatCompletion = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "createChatCompletion");
2586
- const {
2587
- data: {
2588
- response,
2589
- prompt_tokens = 0,
2590
- completion_tokens = 0,
2591
- success: aiSuccess = false
2592
- // the AI was able to generate a response
2593
- }
2594
- } = await (createChatCompletion == null ? void 0 : createChatCompletion({
2595
- chat: {
2596
- model: isFreeResponse ? "gpt-4-1106-preview" : "gpt-3.5-turbo-1106",
2597
- messages,
2598
- temperature: 0.7,
2599
- ...responseTool
2600
- },
2601
- type: isFreeResponse ? "LONG_RESPONSE" : "SHORT_RESPONSE"
2602
- }));
2603
- const functionArguments = JSON.parse(((_e = (_d = (_c = response == null ? void 0 : response.tool_calls) == null ? void 0 : _c[0]) == null ? void 0 : _d.function) == null ? void 0 : _e.arguments) || "{}");
2604
- const result = {
2605
- ...functionArguments,
2606
- prompt_tokens,
2607
- completion_tokens,
2608
- aiSuccess
2609
- };
2610
- onCompletionSuccess(result);
2611
- return result;
2612
- } catch (error) {
2613
- onCompletionError({
2614
- type: "COMPLETION",
2615
- message: (error == null ? void 0 : error.message) || "Error getting completion"
2616
- });
2617
- throw new Error(error);
2618
- }
2619
- };
2620
- const getFeedback = async ({
2621
- cardId,
2622
- language = "en",
2623
- // required
2624
- writtenResponse = null,
2625
- // if the type = RESPOND_WRITE
2626
- audio = null,
2627
- autoGrade = true,
2628
- file = null
2629
- }) => {
2630
- try {
2631
- if (!(feedbackAccess == null ? void 0 : feedbackAccess.canAccessFeedback)) {
2632
- const result = {
2633
- noFeedbackAvailable: true,
2634
- success: true,
2635
- reason: (feedbackAccess == null ? void 0 : feedbackAccess.reason) || "No feedback access",
2636
- accessType: (feedbackAccess == null ? void 0 : feedbackAccess.accessType) || "none"
2637
- };
2638
- onCompletionSuccess(result);
2639
- return result;
2640
- }
2641
- let transcript;
2642
- let audioUrl = void 0;
2643
- if (writtenResponse) {
2644
- transcript = writtenResponse;
2645
- onTranscriptSuccess(writtenResponse);
2646
- } else if (typeof audio === "string" && file) {
2647
- if (feedbackAccess == null ? void 0 : feedbackAccess.canAccessFeedback) {
2648
- transcript = await getTranscript(audio, language);
2649
- audioUrl = audio;
2650
- onTranscriptSuccess(transcript);
2651
- } else {
2652
- console.info(
2653
- `Transcript not available: ${(feedbackAccess == null ? void 0 : feedbackAccess.reason) || "No feedback access"}`
2654
- );
2655
- }
2656
- } else {
2657
- const response = await uploadAudioAndGetTranscript(audio || "", language);
2658
- transcript = response.transcript;
2659
- audioUrl = response.audioUrl;
2660
- }
2661
- onGetAudioUrlAndTranscript == null ? void 0 : onGetAudioUrlAndTranscript({ transcript, audioUrl });
2662
- if (feedbackAccess == null ? void 0 : feedbackAccess.canAccessFeedback) {
2663
- const results = await getAIResponse({
2664
- cardId,
2665
- transcript: transcript || ""
2666
- });
2667
- let output = results;
2668
- if (!autoGrade) {
2669
- output = {
2670
- ...output,
2671
- noFeedbackAvailable: true,
2672
- success: true
2673
- };
2674
- }
2675
- onCompletionSuccess(output);
2676
- return output;
2677
- } else {
2678
- const result = {
2679
- noFeedbackAvailable: true,
2680
- success: true,
2681
- reason: (feedbackAccess == null ? void 0 : feedbackAccess.reason) || "No feedback access",
2682
- accessType: (feedbackAccess == null ? void 0 : feedbackAccess.accessType) || "none"
2683
- };
2684
- onCompletionSuccess(result);
2685
- return result;
2686
- }
2687
- } catch (error) {
2688
- console.error("Error getting feedback:", error);
2689
- throw new Error(error);
2690
- }
2691
- };
2692
- const getAIResponse = async ({ cardId, transcript }) => {
2693
- var _a, _b, _c, _d, _e;
2694
- try {
2695
- const getGeminiFeedback = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "callGetFeedback");
2696
- const getProficiencyEstimate = (_d = (_c = api).httpsCallable) == null ? void 0 : _d.call(_c, "getProficiencyEstimate");
2697
- const card = getCardFromCache({
2698
- cardId,
2699
- queryClient
2700
- });
2701
- let feedbackData;
2702
- let proficiencyData = {};
2703
- if (card && card.grading_method === "manual") {
2704
- } else if (card && card.grading_method !== "standards_based") {
2705
- const [geminiResult, proficiencyResult] = await Promise.all([
2706
- getGeminiFeedback == null ? void 0 : getGeminiFeedback({
2707
- cardId,
2708
- studentId: currentUserId,
2709
- studentResponse: transcript
2710
- }),
2711
- getProficiencyEstimate == null ? void 0 : getProficiencyEstimate({
2712
- cardId,
2713
- studentId: currentUserId,
2714
- studentResponse: transcript
2715
- })
2716
- ]);
2717
- proficiencyData = (proficiencyResult == null ? void 0 : proficiencyResult.data) || {};
2718
- feedbackData = {
2719
- ...(_e = geminiResult == null ? void 0 : geminiResult.data) != null ? _e : {},
2720
- // @ts-ignore
2721
- proficiency_level: (proficiencyData == null ? void 0 : proficiencyData.proficiency_level) || null
2722
- };
2723
- } else {
2724
- const geminiResult = await (getGeminiFeedback == null ? void 0 : getGeminiFeedback({
2725
- cardId,
2726
- studentId: currentUserId,
2727
- studentResponse: transcript
2728
- }));
2729
- feedbackData = geminiResult == null ? void 0 : geminiResult.data;
2730
- }
2731
- const results = {
2732
- ...feedbackData,
2733
- // ...proficiencyData,
2734
- aiSuccess: true,
2735
- promptSuccess: (feedbackData == null ? void 0 : feedbackData.success) || false,
2736
- transcript
2737
- };
2738
- return results;
2739
- } catch (error) {
2740
- onCompletionError({
2741
- type: "AI_FEEDBACK",
2742
- message: (error == null ? void 0 : error.message) || "Error getting ai feedback"
2743
- });
2744
- throw new Error(error);
2745
- }
2746
- };
2747
- return {
2748
- submitAudioResponse,
2749
- uploadAudioAndGetTranscript,
2750
- getTranscript,
2751
- getFreeResponseCompletion,
2752
- getFeedback
2753
- };
2754
- };
2755
-
2756
- // src/hooks/useOrganizationAccess.ts
2757
- import { useQuery as useQuery7 } from "@tanstack/react-query";
2758
- var useOrganizationAccess = () => {
2759
- const { user } = useSpeakableApi();
2760
- const email = user.auth.email;
2761
- const query3 = useQuery7({
2762
- queryKey: ["organizationAccess", email],
2763
- queryFn: async () => {
2764
- if (!email) {
2765
- return {
2766
- hasUnlimitedAccess: false,
2767
- subscriptionId: null,
2768
- organizationId: null,
2769
- organizationName: null,
2770
- subscriptionEndDate: null,
2771
- accessType: "individual"
2772
- };
2773
- }
2774
- return getOrganizationAccess(email);
2775
- },
2776
- enabled: !!email,
2777
- // Only run query if we have a user email
2778
- staleTime: 5 * 60 * 1e3,
2779
- // Consider data fresh for 5 minutes
2780
- gcTime: 10 * 60 * 1e3,
2781
- // Keep in cache for 10 minutes
2782
- retry: 2
2783
- // Retry failed requests twice
2784
- });
2785
- return {
2786
- ...query3
2787
- };
2788
- };
2789
- var getOrganizationAccess = async (email) => {
2790
- const { limit: limit3, where: where3 } = api.accessQueryConstraints();
2791
- try {
2792
- const organizationSnapshot = await api.getDocs(
2793
- "organizations",
2794
- where3("members", "array-contains", email),
2795
- where3("masterSubscriptionStatus", "==", "active"),
2796
- limit3(1)
2797
- );
2798
- if (!organizationSnapshot.empty) {
2799
- const orgData = organizationSnapshot.data[0];
2800
- return {
2801
- hasUnlimitedAccess: true,
2802
- subscriptionId: orgData == null ? void 0 : orgData.masterSubscriptionId,
2803
- organizationId: orgData.id,
2804
- organizationName: orgData.name || "Unknown Organization",
2805
- subscriptionEndDate: orgData.masterSubscriptionEndDate || null,
2806
- accessType: "organization"
2807
- };
2808
- }
2809
- const institutionSnapshot = await api.getDocs(
2810
- "institution_subscriptions",
2811
- where3("users", "array-contains", email),
2812
- where3("active", "==", true),
2813
- limit3(1)
2814
- );
2815
- if (!institutionSnapshot.empty) {
2816
- const institutionData = institutionSnapshot.data[0];
2817
- const isUnlimited = (institutionData == null ? void 0 : institutionData.plan) === "organization" || (institutionData == null ? void 0 : institutionData.plan) === "school_starter";
2818
- return {
2819
- hasUnlimitedAccess: isUnlimited,
2820
- subscriptionId: institutionData.id,
2821
- organizationId: institutionData == null ? void 0 : institutionData.institutionId,
2822
- organizationName: institutionData.name || institutionData.institutionId || "Legacy Institution",
2823
- subscriptionEndDate: institutionData.endDate || null,
2824
- accessType: "institution_subscriptions"
2825
- };
2826
- }
2827
- return {
2828
- hasUnlimitedAccess: false,
2829
- subscriptionId: null,
2830
- organizationId: null,
2831
- organizationName: null,
2832
- subscriptionEndDate: null,
2833
- accessType: "individual"
2834
- };
2835
- } catch (error) {
2836
- console.error("Error checking organization access:", error);
2837
- return {
2838
- hasUnlimitedAccess: false,
2839
- subscriptionId: null,
2840
- organizationId: null,
2841
- organizationName: null,
2842
- subscriptionEndDate: null,
2843
- accessType: "individual"
2844
- };
2845
- }
2846
- };
2847
-
2848
- // src/hooks/useUpdateStudentVoc.ts
2849
- var useUpdateStudentVocab = (page) => {
2850
- const { user } = useSpeakableApi();
2851
- const currentUserId = user == null ? void 0 : user.auth.uid;
2852
- if (!page || !currentUserId || !page.target_text || !page.language) {
2853
- return {
2854
- studentVocabMarkVoiceSuccess: void 0,
2855
- studentVocabMarkVoiceFail: void 0
2856
- };
2857
- }
2858
- const getDataObject = () => {
2859
- var _a, _b;
2860
- const { serverTimestamp: serverTimestamp3 } = api.accessHelpers();
2861
- const language = (_a = page.language) != null ? _a : "en";
2862
- const word = (_b = page.target_text) != null ? _b : "";
2863
- const phrase_length = getPhraseLength(word);
2864
- const wordHash = getWordHash(word, language);
2865
- const docPath = `users/${currentUserId}/vocab/${wordHash}`;
2866
- const communityPath = `checked-pronunciations/${wordHash}`;
2867
- const id = `${language}-${cleanString(word)}`;
2868
- const data = {
2869
- id,
2870
- word,
2871
- words: (word == null ? void 0 : word.split(" ")) || [],
2872
- wordHash,
2873
- language,
2874
- lastSeen: serverTimestamp3(),
2875
- phrase_length
2876
- };
2877
- return {
2878
- docPath,
2879
- communityPath,
2880
- data
2881
- };
2882
- };
2883
- const markVoiceSuccess = async () => {
2884
- const { docPath, communityPath, data } = getDataObject();
2885
- const { increment: increment3 } = api.accessQueryConstraints();
2886
- const { serverTimestamp: serverTimestamp3 } = api.accessHelpers();
2887
- data.voiceSuccess = increment3(1);
2888
- try {
2889
- await api.updateDoc(docPath, data);
2890
- } catch (error) {
2891
- if (error instanceof Error && error.message === "not-found") {
2892
- data.firstSeen = serverTimestamp3();
2893
- await api.setDoc(docPath, data, { merge: true });
2894
- } else {
2895
- console.log(error);
2896
- }
2897
- }
2898
- try {
2899
- data.pronunciations = increment3(1);
2900
- await api.setDoc(communityPath, data, { merge: true });
2901
- } catch (error) {
2902
- console.log(error);
2903
- }
2904
- };
2905
- const markVoiceFail = async () => {
2906
- const { docPath, communityPath, data } = getDataObject();
2907
- const { increment: increment3 } = api.accessQueryConstraints();
2908
- const { serverTimestamp: serverTimestamp3 } = api.accessHelpers();
2909
- data.voiceFail = increment3(1);
2910
- try {
2911
- await api.updateDoc(docPath, data);
2912
- } catch (error) {
2913
- if (error instanceof Error && error.message === "not-found") {
2914
- data.firstSeen = serverTimestamp3();
2915
- await api.setDoc(docPath, data, { merge: true });
2916
- } else {
2917
- console.log(error);
2918
- }
2919
- }
2920
- try {
2921
- data.fails = increment3(1);
2922
- await api.setDoc(communityPath, data, { merge: true });
2923
- } catch (error) {
2924
- console.log(error);
2925
- }
2926
- };
2927
- return {
2928
- studentVocabMarkVoiceSuccess: markVoiceSuccess,
2929
- studentVocabMarkVoiceFail: markVoiceFail
2930
- };
2931
- };
2932
-
2933
- // src/hooks/useUserPlan.ts
2934
- function useUserPlan() {
2935
- const { permissions } = useSpeakableApi();
2936
- const checkIsTeacherProPlan = (plan) => plan === SpeakablePlanTypes.teacher_pro || plan === SpeakablePlanTypes.starter;
2937
- const checkIsOrganizationPlan = (plan) => plan === SpeakablePlanTypes.organization || plan === SpeakablePlanTypes.professional || plan === SpeakablePlanTypes.growth;
2938
- const checkIsSchoolStarter = (plan) => plan === SpeakablePlanTypes.school_starter;
2939
- const checkIsFreePlan = (plan) => plan === SpeakablePlanTypes.basic || !plan;
2940
- return {
2941
- userPlan: permissions.plan,
2942
- loaded: !!permissions.plan,
2943
- isFreePlan: checkIsFreePlan(permissions.plan),
2944
- isTeacherProPlan: checkIsTeacherProPlan(permissions.plan),
2945
- isOrganizationPlan: checkIsOrganizationPlan(permissions.plan),
2946
- isSchoolStarter: checkIsSchoolStarter(permissions.plan),
2947
- checkIsFreePlan,
2948
- checkIsTeacherProPlan,
2949
- checkIsOrganizationPlan
2950
- };
2951
- }
2952
-
2953
- // src/domains/assignment/utils/check-assignment-availability.ts
2954
- import dayjs4 from "dayjs";
2955
- var checkAssignmentAvailability = (scheduledTime) => {
2956
- if (!scheduledTime) return true;
2957
- const scheduledDate = typeof scheduledTime === "string" ? dayjs4(scheduledTime) : dayjs4(scheduledTime.toDate());
2958
- if (!scheduledDate.isValid()) return true;
2959
- return dayjs4().isAfter(scheduledDate);
2960
- };
2961
-
2962
- // src/domains/cards/utils/check-page-type.ts
2963
- function checkIsRepeatPage(cardType) {
2964
- if (cardType === void 0) return false;
2965
- return REPEAT_PAGE_ACTIVITY_TYPES.includes(cardType);
2966
- }
2967
- function checkIsMCPage(cardType) {
2968
- if (cardType === void 0) return false;
2969
- return MULTIPLE_CHOICE_PAGE_ACTIVITY_TYPES.includes(cardType);
2970
- }
2971
- function checkIsRespondPage(cardType) {
2972
- if (cardType === void 0) return false;
2973
- return RESPOND_PAGE_ACTIVITY_TYPES.includes(cardType);
2974
- }
2975
- function checkIsRespondWrittenPage(cardType) {
2976
- if (cardType === void 0) return false;
2977
- return RESPOND_WRITE_PAGE_ACTIVITY_TYPES.includes(cardType);
2978
- }
2979
- function checkIsRespondAudioPage(cardType) {
2980
- if (cardType === void 0) return false;
2981
- return RESPOND_AUDIO_PAGE_ACTIVITY_TYPES.includes(cardType);
2982
- }
2983
- var checkIsMediaPage = (cardType) => {
2984
- if (cardType === void 0) return false;
2985
- return cardType === "MEDIA_PAGE" /* MEDIA_PAGE */;
2986
- };
2987
- var checkIsShortAnswerPage = (cardType) => {
2988
- if (cardType === void 0) return false;
2989
- return cardType === "SHORT_ANSWER" /* SHORT_ANSWER */;
2990
- };
2991
- var checkTypePageActivity = (cardType) => {
2992
- const isRespondAudio = checkIsRespondAudioPage(cardType);
2993
- const isRespondWritten = checkIsRespondWrittenPage(cardType);
2994
- const isRespond = checkIsRespondPage(cardType);
2995
- const isMC = checkIsMCPage(cardType);
2996
- const isRepeat = checkIsRepeatPage(cardType);
2997
- const isMediaPage = checkIsMediaPage(cardType);
2998
- const isShortAnswer = checkIsShortAnswerPage(cardType);
2999
- return {
3000
- isRespondAudio,
3001
- isRespondWritten,
3002
- isRespond,
3003
- isMC,
3004
- isRepeat,
3005
- isMediaPage,
3006
- isShortAnswer
3007
- };
3008
- };
3009
-
3010
- // src/domains/cards/utils/get-page-prompt.ts
3011
- function extractTextFromRichText(richText) {
3012
- if (!richText) return "";
3013
- return richText.replace(/<[^>]*>/g, "").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").trim();
3014
- }
3015
- function getPagePrompt(card) {
3016
- if (!card) return { has: false, text: "", rich_text: "", isTextEqualToRichText: false };
3017
- const { isMC, isRepeat, isRespond, isShortAnswer } = checkTypePageActivity(card == null ? void 0 : card.type);
3018
- const hidePrompt = (card == null ? void 0 : card.hidePrompt) === true;
3019
- const createReturnObject = (text, richText) => {
3020
- const plainText = text || "";
3021
- const richTextPlain = extractTextFromRichText(richText);
3022
- return {
3023
- has: true,
3024
- text: plainText,
3025
- rich_text: richText || "",
3026
- isTextEqualToRichText: plainText.trim() === richTextPlain.trim()
3027
- };
3028
- };
3029
- if (isRepeat) {
3030
- return createReturnObject(card == null ? void 0 : card.target_text, card == null ? void 0 : card.rich_text);
3031
- }
3032
- if (isRespond && !hidePrompt) {
3033
- return createReturnObject(card == null ? void 0 : card.prompt, card == null ? void 0 : card.rich_text);
3034
- }
3035
- if (isMC) {
3036
- return createReturnObject(card == null ? void 0 : card.question, card == null ? void 0 : card.rich_text);
3037
- }
3038
- if (isShortAnswer && !hidePrompt) {
3039
- return createReturnObject(card == null ? void 0 : card.prompt, card == null ? void 0 : card.rich_text);
3040
- }
3041
- return {
3042
- has: false,
3043
- text: "",
3044
- rich_text: "",
3045
- isTextEqualToRichText: false
3046
- };
3047
- }
3048
-
3049
- // src/domains/cards/utils/get-completed-pages.ts
3050
- var getTotalCompletedCards = (pageScores) => {
3051
- return Object.values(pageScores != null ? pageScores : {}).reduce((acc, cardScore) => {
3052
- var _a, _b;
3053
- if (((_b = (_a = cardScore.completed) != null ? _a : cardScore.score) != null ? _b : cardScore.score === 0) && !cardScore.media_area_opened) {
3054
- acc++;
3055
- }
3056
- return acc;
3057
- }, 0);
3058
- };
3059
-
3060
- // src/domains/cards/utils/get-label-page.ts
3061
- var labels = {
3062
- repeat: {
3063
- short: "Repeat",
3064
- long: "Listen & Repeat"
3065
- },
3066
- mc: {
3067
- short: "Multiple Choice",
3068
- long: "Multiple Choice"
3069
- },
3070
- mediaPage: {
3071
- short: "Media Page",
3072
- long: "Media Page"
3073
- },
3074
- shortAnswer: {
3075
- short: "Short Answer",
3076
- long: "Short Answer"
3077
- },
3078
- respondWritten: {
3079
- short: "Open Response",
3080
- long: "Written Open Response"
3081
- },
3082
- respondAudio: {
3083
- short: "Open Response",
3084
- long: "Spoken Open Response"
3085
- }
3086
- };
3087
- var getLabelPage = (pageType) => {
3088
- if (!pageType) {
3089
- return {
3090
- short: "",
3091
- long: ""
3092
- };
3093
- }
3094
- const { isRepeat, isMC, isMediaPage, isShortAnswer, isRespondWritten, isRespondAudio } = checkTypePageActivity(pageType);
3095
- if (isRepeat) {
3096
- return labels.repeat;
3097
- }
3098
- if (isMC) {
3099
- return labels.mc;
3100
- }
3101
- if (isMediaPage) {
3102
- return labels.mediaPage;
3103
- }
3104
- if (isShortAnswer) {
3105
- return labels.shortAnswer;
3106
- }
3107
- if (isRespondWritten) {
3108
- return labels.respondWritten;
3109
- }
3110
- if (isRespondAudio) {
3111
- return labels.respondAudio;
3112
- }
3113
- return {
3114
- short: "",
3115
- long: ""
3116
- };
3117
- };
3118
-
3119
- // src/domains/assignment/services/get-assignments-score.service.ts
3120
- var _getAssignmentScores = async ({
3121
- assignmentId,
3122
- analyticType = "macro" /* Macro */,
3123
- studentId,
3124
- currentUserId
3125
- }) => {
3126
- if (analyticType === "student" /* Student */) {
3127
- const path = refsAssignmentFiresotre.assignmentScores({
3128
- id: assignmentId,
3129
- userId: currentUserId
3130
- });
3131
- const response = await api.getDoc(path);
3132
- return { scores: response.data, id: assignmentId };
3133
- }
3134
- if (analyticType === "student_summary" /* StudentSummary */ && studentId) {
3135
- const path = refsAssignmentFiresotre.assignmentScores({
3136
- id: assignmentId,
3137
- userId: studentId
3138
- });
3139
- const response = await api.getDoc(path);
3140
- return { scores: response.data, id: assignmentId };
3141
- }
3142
- if (analyticType !== "all" /* All */ && ASSIGNMENT_ANALYTICS_TYPES.includes(analyticType)) {
3143
- const ref = refsAssignmentFiresotre.assignmentAnalytics({
3144
- id: assignmentId,
3145
- type: analyticType
3146
- });
3147
- const docData = await api.getDoc(ref);
3148
- return { scores: docData.data, id: assignmentId };
3149
- } else if (analyticType === "all" /* All */) {
3150
- const ref = refsAssignmentFiresotre.assignmentAllAnalytics({ id: assignmentId });
3151
- const response = await api.getDocs(ref);
3152
- const data = response.data.reduce((acc, curr) => {
3153
- acc[curr.id] = curr;
3154
- return acc;
3155
- }, {});
3156
- return { scores: data, id: assignmentId };
3157
- }
3158
- };
3159
- var getAssignmentScores = withErrorHandler(_getAssignmentScores, "getAssignmentScores");
3160
-
3161
- // src/domains/assignment/services/attach-score-assignment.service.ts
3162
- var _attachScoresAssignment = async ({
3163
- assignments,
3164
- analyticType,
3165
- studentId,
3166
- currentUserId
3167
- }) => {
3168
- const scoresPromises = assignments.map((a) => {
3169
- return getAssignmentScores({
3170
- assignmentId: a.id,
3171
- analyticType,
3172
- studentId,
3173
- currentUserId
3174
- });
3175
- });
3176
- const scores = await Promise.all(scoresPromises);
3177
- const scoresObject = scores.reduce((acc, curr) => {
3178
- acc[curr.id] = curr.scores;
3179
- return acc;
3180
- }, {});
3181
- const assignmentsWithScores = assignments.map((a) => {
3182
- var _a;
3183
- return {
3184
- ...a,
3185
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/ban-ts-comment
3186
- // @ts-ignore
3187
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
3188
- scores: (_a = scoresObject[a.id]) != null ? _a : null
3189
- };
3190
- });
3191
- return assignmentsWithScores;
3192
- };
3193
- var attachScoresAssignment = withErrorHandler(
3194
- _attachScoresAssignment,
3195
- "attachScoresAssignment"
3196
- );
3197
-
3198
- // src/domains/assignment/services/get-all-assignment.service.ts
3199
- async function _getAllAssignments() {
3200
- const path = refsAssignmentFiresotre.allAssignments();
3201
- const response = await api.getDocs(path);
3202
- return response.data;
3203
- }
3204
- var getAllAssignments = withErrorHandler(_getAllAssignments, "getAllAssignments");
3205
-
3206
- // src/domains/assignment/services/get-assignment.service.ts
3207
- async function _getAssignment(params) {
3208
- var _a;
3209
- const path = refsAssignmentFiresotre.assignment({ id: params.assignmentId });
3210
- const response = await api.getDoc(path);
3211
- if (!response.data) return null;
3212
- const assignment = response.data;
3213
- const isAvailable = checkAssignmentAvailability(assignment.scheduledTime);
3214
- const assignmentWithId = {
3215
- ...assignment,
3216
- isAvailable,
3217
- id: params.assignmentId,
3218
- scheduledTime: (_a = assignment.scheduledTime) != null ? _a : null
3219
- };
3220
- if (params.analyticType) {
3221
- const assignmentsWithScores = await attachScoresAssignment({
3222
- assignments: [assignmentWithId],
3223
- analyticType: params.analyticType,
3224
- currentUserId: params.currentUserId
3225
- });
3226
- return assignmentsWithScores.length > 0 ? assignmentsWithScores[0] : assignmentWithId;
3227
- }
3228
- return assignmentWithId;
3229
- }
3230
- var getAssignment = withErrorHandler(_getAssignment, "getAssignment");
3231
-
3232
- // src/domains/assignment/assignment.repo.ts
3233
- var createAssignmentRepo = () => {
3234
- return {
3235
- getAssignment,
3236
- attachScoresAssignment,
3237
- getAssignmentScores,
3238
- getAllAssignments
3239
- };
3240
- };
3241
-
3242
- // src/domains/cards/card.repo.ts
3243
- var createCardRepo = () => {
3244
- return {
3245
- createCard,
3246
- createCards,
3247
- getCard
3248
- };
3249
- };
3250
-
3251
- // src/domains/sets/set.repo.ts
3252
- var createSetRepo = () => {
3253
- return {
3254
- getSet
3255
- };
3256
- };
3257
-
3258
- // src/lib/create-firebase-client-web.ts
3259
- import {
3260
- getDoc,
3261
- getDocs,
3262
- addDoc,
3263
- setDoc,
3264
- updateDoc,
3265
- deleteDoc,
3266
- runTransaction,
3267
- writeBatch,
3268
- doc,
3269
- collection,
3270
- query,
3271
- serverTimestamp,
3272
- orderBy,
3273
- limit,
3274
- startAt,
3275
- startAfter,
3276
- endAt,
3277
- endBefore,
3278
- where,
3279
- increment
3280
- } from "firebase/firestore";
3281
-
3282
- // src/lib/create-firebase-client.ts
3283
- function createFsClientBase({
3284
- db,
3285
- helpers,
3286
- httpsCallable,
3287
- logEvent
3288
- }) {
3289
- const dbAsFirestore = db;
3290
- api.initialize({
3291
- db: dbAsFirestore,
3292
- helpers,
3293
- httpsCallable,
3294
- logEvent
3295
- });
3296
- return {
3297
- assignmentRepo: createAssignmentRepo(),
3298
- cardRepo: createCardRepo()
3299
- };
3300
- }
3301
-
3302
- // src/lib/create-firebase-client-web.ts
3303
- var createFsClientWeb = ({ db, httpsCallable, logEvent }) => {
3304
- return createFsClientBase({
3305
- db,
3306
- httpsCallable,
3307
- logEvent,
3308
- helpers: {
3309
- getDoc,
3310
- getDocs,
3311
- addDoc,
3312
- setDoc,
3313
- updateDoc,
3314
- deleteDoc,
3315
- runTransaction,
3316
- writeBatch,
3317
- doc,
3318
- collection,
3319
- query,
3320
- serverTimestamp,
3321
- orderBy,
3322
- limit,
3323
- startAt,
3324
- startAfter,
3325
- endAt,
3326
- endBefore,
3327
- where,
3328
- increment
3329
- }
3330
- });
3331
- };
3332
-
3333
- // src/lib/create-firebase-client-native.ts
3334
- import {
3335
- getDoc as getDoc2,
3336
- getDocs as getDocs2,
3337
- addDoc as addDoc2,
3338
- setDoc as setDoc2,
3339
- updateDoc as updateDoc2,
3340
- deleteDoc as deleteDoc2,
3341
- runTransaction as runTransaction2,
3342
- writeBatch as writeBatch2,
3343
- doc as doc2,
3344
- collection as collection2,
3345
- query as query2,
3346
- serverTimestamp as serverTimestamp2,
3347
- orderBy as orderBy2,
3348
- limit as limit2,
3349
- startAt as startAt2,
3350
- startAfter as startAfter2,
3351
- endAt as endAt2,
3352
- endBefore as endBefore2,
3353
- where as where2,
3354
- increment as increment2
3355
- } from "@react-native-firebase/firestore";
3356
- var createFsClientNative = ({ db, httpsCallable, logEvent }) => {
3357
- return createFsClientBase({
3358
- db,
3359
- httpsCallable,
3360
- logEvent,
3361
- helpers: {
3362
- getDoc: getDoc2,
3363
- getDocs: getDocs2,
3364
- addDoc: addDoc2,
3365
- setDoc: setDoc2,
3366
- updateDoc: updateDoc2,
3367
- deleteDoc: deleteDoc2,
3368
- runTransaction: runTransaction2,
3369
- writeBatch: writeBatch2,
3370
- doc: doc2,
3371
- collection: collection2,
3372
- query: query2,
3373
- serverTimestamp: serverTimestamp2,
3374
- orderBy: orderBy2,
3375
- limit: limit2,
3376
- startAt: startAt2,
3377
- startAfter: startAfter2,
3378
- endAt: endAt2,
3379
- endBefore: endBefore2,
3380
- where: where2,
3381
- increment: increment2
3382
- }
3383
- });
3384
- };
3385
- export {
3386
- AI_ASSISTANT_PLANS,
3387
- ANALYTICS_EVENT_TYPES,
3388
- ANALYTICS_PLANS,
3389
- ASSIGNMENT_SETTINGS_PLANS,
3390
- AUTO_GRADING_PLANS,
3391
- ActivityPageType,
3392
- COMMENTS_PLANS,
3393
- DISCOVER_PLANS,
3394
- FEEDBACK_PLANS,
3395
- FREE_PLAN,
3396
- FirebaseAPI,
3397
- FsCtx,
3398
- INTEGRATIONS_PLANS,
3399
- MEDIA_AREA_PLANS,
3400
- MULTIPLE_CHOICE_PAGE_ACTIVITY_TYPES,
3401
- ORGANIZATION_PLAN,
3402
- REPEAT_PAGE_ACTIVITY_TYPES,
3403
- RESPOND_AUDIO_PAGE_ACTIVITY_TYPES,
3404
- RESPOND_PAGE_ACTIVITY_TYPES,
3405
- RESPOND_WRITE_PAGE_ACTIVITY_TYPES,
3406
- SCHOOL_STARTER,
3407
- SPACES_PLANS,
3408
- SpeakablePermissionsMap,
3409
- SpeakablePlanHierarchy,
3410
- SpeakablePlanTypes,
3411
- SpeakableProvider,
3412
- TEACHER_PRO_PLAN,
3413
- WEB_BASE_URL,
3414
- _getAllAssignments,
3415
- activityFeedbackAccessQueryKeys,
3416
- addGradingStandardLog,
3417
- api,
3418
- assignmentQueryKeys,
3419
- attachScoresAssignment,
3420
- cardsQueryKeys,
3421
- checkAssignmentAvailability,
3422
- checkTypePageActivity,
3423
- cleanString,
3424
- clearScore,
3425
- createAssignmentRepo,
3426
- createCard,
3427
- createCardRepo,
3428
- createCards,
3429
- createFsClientWeb as createFsClient,
3430
- createFsClientNative,
3431
- createNotification,
3432
- createScore,
3433
- createSetRepo,
3434
- creditQueryKeys,
3435
- debounce,
3436
- defaultScore,
3437
- getAllAssignments,
3438
- getAssignment,
3439
- getAssignmentScore,
3440
- getAssignmentScores,
3441
- getCard,
3442
- getCardFromCache,
3443
- getLabelPage,
3444
- getPagePrompt,
3445
- getPhraseLength,
3446
- getPracticeScore,
3447
- getRespondCardTool,
3448
- getScore,
3449
- getSet,
3450
- getSetFromCache,
3451
- getTotalCompletedCards,
3452
- getVerificationStatus,
3453
- getWordHash,
3454
- logCreateAssignment,
3455
- logFreePlanRespond,
3456
- logFreePlanWrittenResponse,
3457
- logGradingStandardLog,
3458
- logMultipleChoiceError,
3459
- logMultipleChoiceFail,
3460
- logMultipleChoiceSuccess,
3461
- logOpenActivityPreview,
3462
- logOpenAssignment,
3463
- logRepeatFail,
3464
- logRepeatSuccess,
3465
- logRespondError,
3466
- logRespondFail,
3467
- logRespondSubmitted,
3468
- logRespondSuccess,
3469
- logStartAssignment,
3470
- logSubmitAssignment,
3471
- logWrittenResponseError,
3472
- logWrittenResponseFail,
3473
- logWrittenResponseSubmitted,
3474
- logWrittenResponseSuccess,
3475
- purify,
3476
- scoreQueryKeys,
3477
- sendNotification,
3478
- setsQueryKeys,
3479
- submitAssignmentScore,
3480
- submitPracticeScore,
3481
- updateCardInCache,
3482
- updateCardScore,
3483
- updateScore,
3484
- updateSetInCache,
3485
- useActivity,
3486
- useActivityFeedbackAccess,
3487
- useActivityTracker,
3488
- useAssignment,
3489
- useBaseOpenAI,
3490
- useCards,
3491
- useClearScore,
3492
- useCreateCard,
3493
- useCreateCards,
3494
- useCreateNotification,
3495
- useGetCard,
3496
- useGoogleClassroom,
3497
- useOrganizationAccess,
3498
- useScore,
3499
- useSet,
3500
- useSpeakableApi,
3501
- useSubmitAssignmentScore,
3502
- useSubmitPracticeScore,
3503
- useUpdateCardScore,
3504
- useUpdateScore,
3505
- useUpdateStudentVocab,
3506
- useUserCredits,
3507
- useUserPlan
3508
- };
3509
- //# sourceMappingURL=everything.js.map