@speakableio/core 1.0.19 → 1.0.20

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.
@@ -30,114 +30,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/entry-points/index.native.ts
31
31
  var index_native_exports = {};
32
32
  __export(index_native_exports, {
33
- ActivityPageType: () => ActivityPageType,
34
- BASE_MULTIPLE_CHOICE_FIELD_VALUES: () => BASE_MULTIPLE_CHOICE_FIELD_VALUES,
35
- BASE_REPEAT_FIELD_VALUES: () => BASE_REPEAT_FIELD_VALUES,
36
- BASE_RESPOND_FIELD_VALUES: () => BASE_RESPOND_FIELD_VALUES,
37
- FeedbackTypesCard: () => FeedbackTypesCard,
38
- FsCtx: () => FsCtx,
39
- LENIENCY_OPTIONS: () => LENIENCY_OPTIONS,
40
- LeniencyCard: () => LeniencyCard,
41
- MULTIPLE_CHOICE_PAGE_ACTIVITY_TYPES: () => MULTIPLE_CHOICE_PAGE_ACTIVITY_TYPES,
42
- REPEAT_PAGE_ACTIVITY_TYPES: () => REPEAT_PAGE_ACTIVITY_TYPES,
43
- RESPOND_AUDIO_PAGE_ACTIVITY_TYPES: () => RESPOND_AUDIO_PAGE_ACTIVITY_TYPES,
44
- RESPOND_PAGE_ACTIVITY_TYPES: () => RESPOND_PAGE_ACTIVITY_TYPES,
45
- RESPOND_WRITE_PAGE_ACTIVITY_TYPES: () => RESPOND_WRITE_PAGE_ACTIVITY_TYPES,
46
- SPEAKABLE_NOTIFICATIONS: () => SPEAKABLE_NOTIFICATIONS,
47
- STUDENT_LEVELS_OPTIONS: () => STUDENT_LEVELS_OPTIONS,
48
- SpeakableNotificationTypes: () => SpeakableNotificationTypes,
49
- SpeakableProvider: () => SpeakableProvider,
50
- VerificationCardStatus: () => VerificationCardStatus,
51
- assignmentQueryKeys: () => assignmentQueryKeys,
52
- cardsQueryKeys: () => cardsQueryKeys,
53
- checkIsMCPage: () => checkIsMCPage,
54
- checkIsMediaPage: () => checkIsMediaPage,
55
- checkIsRepeatPage: () => checkIsRepeatPage,
56
- checkIsRespondAudioPage: () => checkIsRespondAudioPage,
57
- checkIsRespondPage: () => checkIsRespondPage,
58
- checkIsRespondWrittenPage: () => checkIsRespondWrittenPage,
59
- checkIsShortAnswerPage: () => checkIsShortAnswerPage,
60
- checkTypePageActivity: () => checkTypePageActivity,
61
- cleanString: () => cleanString,
62
- createAssignmentRepo: () => createAssignmentRepo,
63
- createCardRepo: () => createCardRepo,
64
- createFsClient: () => createFsClientNative,
65
- createSetRepo: () => createSetRepo,
66
- creditQueryKeys: () => creditQueryKeys,
67
- debounce: () => debounce,
68
- getCardFromCache: () => getCardFromCache,
69
- getLabelPage: () => getLabelPage,
70
- getPagePrompt: () => getPagePrompt,
71
- getPhraseLength: () => getPhraseLength,
72
- getRespondCardTool: () => getRespondCardTool,
73
- getSetFromCache: () => getSetFromCache,
74
- getTotalCompletedCards: () => getTotalCompletedCards,
75
- getWordHash: () => getWordHash,
76
- purify: () => purify,
77
- refsCardsFiresotre: () => refsCardsFiresotre,
78
- refsSetsFirestore: () => refsSetsFirestore,
79
- scoreQueryKeys: () => scoreQueryKeys,
80
- setsQueryKeys: () => setsQueryKeys,
81
- updateCardInCache: () => updateCardInCache,
82
- updateSetInCache: () => updateSetInCache,
83
- useActivity: () => useActivity,
84
- useActivityFeedbackAccess: () => useActivityFeedbackAccess,
85
- useAssignment: () => useAssignment,
86
- useBaseOpenAI: () => useBaseOpenAI,
87
- useCards: () => useCards,
88
- useClearScore: () => useClearScore,
89
- useClearScoreV2: () => useClearScoreV2,
90
- useCreateCard: () => useCreateCard,
91
- useCreateCards: () => useCreateCards,
92
- useCreateNotification: () => useCreateNotification,
93
- useGetCard: () => useGetCard,
94
- useOrganizationAccess: () => useOrganizationAccess,
95
- useScore: () => useScore,
96
- useSet: () => useSet,
97
- useSpeakableApi: () => useSpeakableApi,
98
- useSubmitAssignmentScore: () => useSubmitAssignmentScore,
99
- useSubmitPracticeScore: () => useSubmitPracticeScore,
100
- useUpdateCardScore: () => useUpdateCardScore,
101
- useUpdateScore: () => useUpdateScore,
102
- useUpdateStudentVocab: () => useUpdateStudentVocab,
103
- useUserCredits: () => useUserCredits
33
+ createFsClient: () => createFsClientNative
104
34
  });
105
35
  module.exports = __toCommonJS(index_native_exports);
106
36
 
107
- // src/providers/SpeakableProvider.tsx
108
- var import_react = require("react");
109
- var import_jsx_runtime = require("react/jsx-runtime");
110
- var FsCtx = (0, import_react.createContext)(null);
111
- function SpeakableProvider({
112
- user,
113
- children,
114
- queryClient,
115
- permissions,
116
- fsClient
117
- }) {
118
- const [speakableApi, setSpeakableApi] = (0, import_react.useState)(null);
119
- (0, import_react.useEffect)(() => {
120
- setSpeakableApi(fsClient);
121
- }, [fsClient]);
122
- if (!speakableApi) return null;
123
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
124
- FsCtx.Provider,
125
- {
126
- value: {
127
- speakableApi,
128
- queryClient,
129
- user,
130
- permissions
131
- },
132
- children
133
- }
134
- );
135
- }
136
- function useSpeakableApi() {
137
- const ctx = (0, import_react.useContext)(FsCtx);
138
- if (!ctx) throw new Error("useSpeakableApi must be used within a SpeakableProvider");
139
- return ctx;
140
- }
37
+ // src/lib/create-firebase-client-native.ts
38
+ var import_firestore = require("@react-native-firebase/firestore");
141
39
 
142
40
  // src/utils/error-handler.ts
143
41
  var ServiceError = class extends Error {
@@ -447,30 +345,13 @@ var createAssignmentRepo = () => {
447
345
  };
448
346
  };
449
347
 
348
+ // src/providers/SpeakableProvider.tsx
349
+ var import_react = require("react");
350
+ var import_jsx_runtime = require("react/jsx-runtime");
351
+ var FsCtx = (0, import_react.createContext)(null);
352
+
450
353
  // src/domains/assignment/hooks/assignment.hooks.ts
451
354
  var import_react_query = require("@tanstack/react-query");
452
- var assignmentQueryKeys = {
453
- all: ["assignments"],
454
- byId: (id) => [...assignmentQueryKeys.all, id],
455
- list: () => [...assignmentQueryKeys.all, "list"]
456
- };
457
- function useAssignment({
458
- assignmentId,
459
- enabled = true,
460
- analyticType,
461
- userId
462
- }) {
463
- const { speakableApi } = useSpeakableApi();
464
- return (0, import_react_query.useQuery)({
465
- queryKey: assignmentQueryKeys.byId(assignmentId),
466
- queryFn: () => speakableApi.assignmentRepo.getAssignment({
467
- assignmentId,
468
- analyticType,
469
- currentUserId: userId
470
- }),
471
- enabled
472
- });
473
- }
474
355
 
475
356
  // src/domains/assignment/hooks/score-hooks.ts
476
357
  var import_react_query2 = require("@tanstack/react-query");
@@ -493,24 +374,6 @@ function debounce(func, waitFor) {
493
374
  });
494
375
  }
495
376
 
496
- // src/lib/tanstack/handle-optimistic-update-query.ts
497
- var handleOptimisticUpdate = async ({
498
- queryClient,
499
- queryKey,
500
- newData
501
- }) => {
502
- await queryClient.cancelQueries({
503
- queryKey
504
- });
505
- const previousData = queryClient.getQueryData(queryKey);
506
- if (previousData === void 0) {
507
- queryClient.setQueryData(queryKey, newData);
508
- } else {
509
- queryClient.setQueryData(queryKey, { ...previousData, ...newData });
510
- }
511
- return { previousData };
512
- };
513
-
514
377
  // src/constants/speakable-plans.ts
515
378
  var FEEDBACK_PLANS = {
516
379
  FEEDBACK_TRANSCRIPT: "FEEDBACK_TRANSCRIPT",
@@ -667,64 +530,9 @@ var SpeakablePlanHierarchy = [
667
530
  SpeakablePlanTypes.organization
668
531
  ];
669
532
 
670
- // src/hooks/usePermissions.ts
671
- var usePermissions = () => {
672
- const { permissions } = useSpeakableApi();
673
- const has = (permission) => {
674
- var _a;
675
- return (_a = permissions.permissions) == null ? void 0 : _a.includes(permission);
676
- };
677
- return {
678
- plan: permissions.plan,
679
- permissionsLoaded: permissions.loaded,
680
- isStripePlan: permissions.isStripePlan,
681
- refreshDate: permissions.refreshDate,
682
- isInstitutionPlan: permissions.isInstitutionPlan,
683
- subscriptionId: permissions.subscriptionId,
684
- contact: permissions.contact,
685
- hasGradebook: has(ANALYTICS_PLANS.ANALYTICS_GRADEBOOK),
686
- hasGoogleClassroomGradePassback: has(ASSIGNMENT_SETTINGS_PLANS.GOOGLE_CLASSROOM_GRADE_PASSBACK),
687
- hasAssessments: has(ASSIGNMENT_SETTINGS_PLANS.ASSESSMENTS),
688
- hasSectionAnalytics: has(ANALYTICS_PLANS.ANALYTICS_CLASSROOM_ANALYTICS),
689
- hasStudentReports: has(ANALYTICS_PLANS.ANALYTICS_STUDENT_PROGRESS_REPORTS),
690
- permissions: permissions || [],
691
- hasStudentPortfolios: permissions.hasStudentPortfolios,
692
- isFreeOrgTrial: permissions.type === "free_org_trial",
693
- freeOrgTrialExpired: permissions.freeOrgTrialExpired
694
- };
695
- };
696
- var usePermissions_default = usePermissions;
697
-
698
- // src/domains/notification/notification.constants.ts
699
- var SPEAKABLE_NOTIFICATIONS = {
700
- NEW_ASSIGNMENT: "new_assignment",
701
- ASSESSMENT_SUBMITTED: "assessment_submitted",
702
- ASSESSMENT_SCORED: "assessment_scored",
703
- NEW_COMMENT: "NEW_COMMENT"
704
- };
705
- var SpeakableNotificationTypes = {
706
- NEW_ASSIGNMENT: "NEW_ASSIGNMENT",
707
- FEEDBACK_FROM_TEACHER: "FEEDBACK_FROM_TEACHER",
708
- MESSAGE_FROM_STUDENT: "MESSAGE_FROM_STUDENT",
709
- PHRASE_MARKED_CORRECT: "PHRASE_MARKED_CORRECT",
710
- STUDENT_PROGRESS: "STUDENT_PROGRESS",
711
- PLAYLIST_FOLLOWERS: "PLAYLIST_FOLLOWERS",
712
- PLAYLIST_PLAYS: "PLAYLIST_PLAYS",
713
- // New notifications
714
- ASSESSMENT_SUBMITTED: "ASSESSMENT_SUBMITTED",
715
- // Notification FOR TEACHER when student submits assessment
716
- ASSESSMENT_SCORED: "ASSESSMENT_SCORED",
717
- // Notification FOR STUDENT when teacher scores assessment
718
- // Comment
719
- NEW_COMMENT: "NEW_COMMENT"
720
- };
721
-
722
533
  // src/domains/notification/services/create-notification.service.ts
723
534
  var import_dayjs2 = __toESM(require("dayjs"));
724
535
 
725
- // src/constants/web.constants.ts
726
- var WEB_BASE_URL = "https://app.speakable.io";
727
-
728
536
  // src/domains/notification/services/send-notification.service.ts
729
537
  var _sendNotification = async (sendTo, notification) => {
730
538
  var _a, _b, _c;
@@ -737,202 +545,6 @@ var _sendNotification = async (sendTo, notification) => {
737
545
  };
738
546
  var sendNotification = withErrorHandler(_sendNotification, "sendNotification");
739
547
 
740
- // src/domains/notification/services/create-notification.service.ts
741
- var createNotification = async ({
742
- data,
743
- type,
744
- userId,
745
- profile
746
- }) => {
747
- let result;
748
- switch (type) {
749
- case SPEAKABLE_NOTIFICATIONS.NEW_ASSIGNMENT:
750
- result = await handleAssignNotifPromise({ data, profile });
751
- break;
752
- case SPEAKABLE_NOTIFICATIONS.ASSESSMENT_SUBMITTED:
753
- result = await createAssessmentSubmissionNotification({
754
- data,
755
- profile,
756
- userId
757
- });
758
- break;
759
- case SPEAKABLE_NOTIFICATIONS.ASSESSMENT_SCORED:
760
- result = await createAssessmentScoredNotification({
761
- data,
762
- profile
763
- });
764
- break;
765
- default:
766
- result = null;
767
- break;
768
- }
769
- return result;
770
- };
771
- var handleAssignNotifPromise = async ({
772
- data: assignments,
773
- profile
774
- }) => {
775
- if (!assignments.length) return;
776
- try {
777
- const notifsPromises = assignments.map(async (assignment) => {
778
- const {
779
- section,
780
- section: { members },
781
- ...rest
782
- } = assignment;
783
- if (!section || !members) throw new Error("Invalid assignment data");
784
- const data = { section, sendTo: members, assignment: { ...rest } };
785
- return createNewAssignmentNotification({ data, profile });
786
- });
787
- await Promise.all(notifsPromises);
788
- return {
789
- success: true,
790
- message: "Assignment notifications sent successfully"
791
- };
792
- } catch (error) {
793
- console.error("Error in handleAssignNotifPromise:", error);
794
- throw error;
795
- }
796
- };
797
- var createNewAssignmentNotification = async ({
798
- data,
799
- profile
800
- }) => {
801
- var _a;
802
- const { assignment, sendTo } = data;
803
- const teacherName = profile.displayName || "Your teacher";
804
- const dueDate = assignment.dueDateTimestamp ? (0, import_dayjs2.default)(assignment.dueDateTimestamp.toDate()).format("MMM Do") : null;
805
- const results = await sendNotification(sendTo, {
806
- courseId: assignment.courseId,
807
- type: SPEAKABLE_NOTIFICATIONS.NEW_ASSIGNMENT,
808
- senderName: teacherName,
809
- link: `${WEB_BASE_URL}/assignment/${assignment.id}`,
810
- messagePreview: `A new assignment "${assignment.name}" is now available. ${dueDate ? `Due ${dueDate}` : ""}`,
811
- title: "New Assignment Available!",
812
- imageUrl: (_a = profile.image) == null ? void 0 : _a.url
813
- });
814
- return results;
815
- };
816
- var createAssessmentSubmissionNotification = async ({
817
- data: assignment,
818
- profile,
819
- userId
820
- }) => {
821
- var _a;
822
- const studentName = profile.displayName || "Your student";
823
- const results = await sendNotification(assignment.owners, {
824
- courseId: assignment.courseId,
825
- type: SPEAKABLE_NOTIFICATIONS.ASSESSMENT_SUBMITTED,
826
- link: `${WEB_BASE_URL}/a/${assignment.id}?studentId=${userId}`,
827
- title: `Assessment Submitted!`,
828
- senderName: studentName,
829
- messagePreview: `${studentName} has submitted the assessment "${assignment.name}"`,
830
- imageUrl: (_a = profile.image) == null ? void 0 : _a.url
831
- });
832
- return results;
833
- };
834
- var createAssessmentScoredNotification = async ({
835
- data,
836
- profile
837
- }) => {
838
- var _a, _b, _c, _d, _e;
839
- const { assignment, sendTo } = data;
840
- const teacherName = profile.displayName || "Your teacher";
841
- const title = `${assignment.isAssessment ? "Assessment" : "Assignment"} Reviewed!`;
842
- const messagePreview = `Your ${assignment.isAssessment ? "assessment" : "assignment"} has been reviewed by your teacher. Click to view the feedback.`;
843
- const results = await sendNotification(sendTo, {
844
- courseId: assignment.courseId,
845
- type: SPEAKABLE_NOTIFICATIONS.ASSESSMENT_SCORED,
846
- link: `${WEB_BASE_URL}/assignment/${assignment.id}`,
847
- title,
848
- messagePreview,
849
- imageUrl: (_a = profile.image) == null ? void 0 : _a.url,
850
- senderName: teacherName
851
- });
852
- await ((_e = (_c = (_b = api).httpsCallable) == null ? void 0 : _c.call(_b, "sendAssessmentScoredEmail")) == null ? void 0 : _e({
853
- assessmentTitle: assignment.name,
854
- link: `${WEB_BASE_URL}/assignment/${assignment.id}`,
855
- senderImage: ((_d = profile.image) == null ? void 0 : _d.url) || "",
856
- studentId: sendTo[0],
857
- teacherName: profile.displayName
858
- }));
859
- return results;
860
- };
861
-
862
- // src/domains/notification/hooks/notification.hooks.ts
863
- var notificationQueryKeys = {
864
- all: ["notifications"],
865
- byId: (id) => [...notificationQueryKeys.all, id]
866
- };
867
- var useCreateNotification = () => {
868
- const { user, queryClient } = useSpeakableApi();
869
- const handleCreateNotifications = async (type, data) => {
870
- var _a, _b;
871
- const result = await createNotification({
872
- type,
873
- userId: user.auth.uid,
874
- profile: (_a = user == null ? void 0 : user.profile) != null ? _a : {},
875
- data
876
- });
877
- queryClient.invalidateQueries({
878
- queryKey: notificationQueryKeys.byId((_b = user == null ? void 0 : user.auth.uid) != null ? _b : "")
879
- });
880
- return result;
881
- };
882
- return {
883
- createNotification: handleCreateNotifications
884
- };
885
- };
886
-
887
- // src/hooks/useGoogleClassroom.ts
888
- var useGoogleClassroom = () => {
889
- const submitAssignmentToGoogleClassroom = async ({
890
- assignment,
891
- scores,
892
- googleUserId = null
893
- // optional to override the user's googleUserId
894
- }) => {
895
- var _a, _b, _c;
896
- try {
897
- const { googleClassroomUserId = null } = scores;
898
- const googleId = googleUserId || googleClassroomUserId;
899
- if (!googleId)
900
- return {
901
- error: true,
902
- message: "No Google Classroom ID found"
903
- };
904
- const { courseWorkId, maxPoints, owners, courseId } = assignment;
905
- const draftGrade = (scores == null ? void 0 : scores.score) ? (scores == null ? void 0 : scores.score) / 100 * maxPoints : 0;
906
- const result = await ((_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "submitAssignmentToGoogleClassroomV2")) == null ? void 0 : _c({
907
- teacherId: owners[0],
908
- courseId,
909
- courseWorkId,
910
- userId: googleId,
911
- draftGrade
912
- }));
913
- return result;
914
- } catch (error) {
915
- return { error: true, message: error.message };
916
- }
917
- };
918
- return {
919
- submitAssignmentToGoogleClassroom
920
- };
921
- };
922
-
923
- // src/lib/firebase/firebase-analytics/grading-standard.ts
924
- var logGradingStandardLog = (data) => {
925
- var _a, _b, _c;
926
- if (data.courseId && data.type && data.level) {
927
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "handleCouresAnalyticsEvent")) == null ? void 0 : _c({
928
- eventType: data.type || "custom",
929
- level: data.level,
930
- courseId: data.courseId
931
- });
932
- }
933
- api.logEvent("logGradingStandard", data);
934
- };
935
-
936
548
  // src/constants/analytics.constants.ts
937
549
  var ANALYTICS_EVENT_TYPES = {
938
550
  VOICE_SUCCESS: "voice_success",
@@ -972,20 +584,6 @@ var ANALYTICS_EVENT_TYPES = {
972
584
  };
973
585
 
974
586
  // src/lib/firebase/firebase-analytics/assignment.ts
975
- var logOpenAssignment = (data = {}) => {
976
- api.logEvent("open_assignment", data);
977
- };
978
- var logOpenActivityPreview = (data = {}) => {
979
- api.logEvent("open_activity_preview", data);
980
- };
981
- var logSubmitAssignment = (data = {}) => {
982
- var _a, _b, _c;
983
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "handleCouresAnalyticsEvent")) == null ? void 0 : _c({
984
- eventType: ANALYTICS_EVENT_TYPES.SUBMISSION,
985
- ...data
986
- });
987
- api.logEvent(ANALYTICS_EVENT_TYPES.SUBMISSION, data);
988
- };
989
587
  var logStartAssignment = (data = {}) => {
990
588
  var _a, _b, _c;
991
589
  if (data.courseId) {
@@ -1228,72 +826,6 @@ var updateCardScore = withErrorHandler(_updateCardScore, "updateCardScore");
1228
826
 
1229
827
  // src/domains/assignment/services/clear-score.service.ts
1230
828
  var import_dayjs3 = __toESM(require("dayjs"));
1231
- async function clearScore(params) {
1232
- var _a, _b, _c, _d, _e;
1233
- const update = {
1234
- [`cards.${params.cardId}`]: {
1235
- attempts: ((_a = params.cardScores.attempts) != null ? _a : 1) + 1,
1236
- correct: (_b = params.cardScores.correct) != null ? _b : 0,
1237
- // save old score history
1238
- history: [
1239
- {
1240
- ...params.cardScores,
1241
- attempts: (_c = params.cardScores.attempts) != null ? _c : 1,
1242
- correct: (_d = params.cardScores.correct) != null ? _d : 0,
1243
- retryTime: (0, import_dayjs3.default)().format("YYYY-MM-DD HH:mm:ss"),
1244
- history: null
1245
- },
1246
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
1247
- ...(_e = params.cardScores.history) != null ? _e : []
1248
- ]
1249
- }
1250
- };
1251
- const path = params.isAssignment ? refsAssignmentFiresotre.assignmentScores({
1252
- id: params.activityId,
1253
- userId: params.userId
1254
- }) : refsScoresPractice.practiceScores({
1255
- setId: params.activityId,
1256
- userId: params.userId
1257
- });
1258
- await api.updateDoc(path, update);
1259
- return {
1260
- update,
1261
- activityId: params.activityId
1262
- };
1263
- }
1264
- async function clearScoreV2(params) {
1265
- var _a, _b, _c, _d, _e;
1266
- const update = {
1267
- [`cards.${params.cardId}`]: {
1268
- ...params.cardScores,
1269
- attempts: ((_a = params.cardScores.attempts) != null ? _a : 1) + 1,
1270
- correct: (_b = params.cardScores.correct) != null ? _b : 0,
1271
- history: [
1272
- {
1273
- ...params.cardScores,
1274
- attempts: (_c = params.cardScores.attempts) != null ? _c : 1,
1275
- correct: (_d = params.cardScores.correct) != null ? _d : 0,
1276
- retryTime: (0, import_dayjs3.default)().format("YYYY-MM-DD HH:mm:ss"),
1277
- history: null
1278
- },
1279
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
1280
- ...(_e = params.cardScores.history) != null ? _e : []
1281
- ]
1282
- }
1283
- };
1284
- const path = params.isAssignment ? refsAssignmentFiresotre.assignmentScores({
1285
- id: params.activityId,
1286
- userId: params.userId
1287
- }) : refsScoresPractice.practiceScores({
1288
- setId: params.activityId,
1289
- userId: params.userId
1290
- });
1291
- await api.updateDoc(path, update);
1292
- return {
1293
- update,
1294
- activityId: params.activityId
1295
- };
1296
- }
1297
829
 
1298
830
  // src/domains/assignment/services/submit-assignment-score.service.ts
1299
831
  var import_dayjs4 = __toESM(require("dayjs"));
@@ -1359,458 +891,15 @@ async function handleCourseAssignment(assignment, userId) {
1359
891
  userId
1360
892
  }));
1361
893
  }
1362
- async function submitPracticeScore({
1363
- setId,
1364
- userId,
1365
- scores
1366
- }) {
1367
- const { serverTimestamp: serverTimestamp2 } = api.accessHelpers();
1368
- const date = (0, import_dayjs4.default)().format("YYYY-MM-DD-HH-mm");
1369
- const ref = refsScoresPractice.practiceScoreHistoryRefDoc({ setId, userId, date });
1370
- const fieldsUpdated = {
1371
- ...scores,
1372
- submitted: true,
1373
- progress: 100,
1374
- submissionDate: serverTimestamp2(),
1375
- status: "SUBMITTED"
1376
- };
1377
- await api.setDoc(ref, { ...fieldsUpdated });
1378
- const refScores = refsScoresPractice.practiceScores({ userId, setId });
1379
- await api.deleteDoc(refScores);
1380
- return { success: true, fieldsUpdated };
1381
- }
1382
894
 
1383
895
  // src/domains/assignment/hooks/score-hooks.ts
1384
- var scoreQueryKeys = {
1385
- all: ["scores"],
1386
- byId: (id) => [...scoreQueryKeys.all, id],
1387
- list: () => [...scoreQueryKeys.all, "list"]
1388
- };
1389
- function useScore({
1390
- isAssignment,
1391
- activityId,
1392
- userId = "",
1393
- courseId,
1394
- enabled = true,
1395
- googleClassroomUserId
1396
- }) {
1397
- return (0, import_react_query2.useQuery)({
1398
- queryFn: () => getScore({
1399
- userId,
1400
- courseId,
1401
- activityId,
1402
- googleClassroomUserId,
1403
- isAssignment
1404
- }),
1405
- queryKey: scoreQueryKeys.byId(activityId),
1406
- enabled
1407
- });
1408
- }
1409
896
  var debounceUpdateScore = debounce(updateScore, 500);
1410
- function useUpdateScore() {
1411
- const { queryClient } = useSpeakableApi();
1412
- const mutation = (0, import_react_query2.useMutation)({
1413
- mutationFn: debounceUpdateScore,
1414
- onMutate: (variables) => {
1415
- return handleOptimisticUpdate({
1416
- queryClient,
1417
- queryKey: scoreQueryKeys.byId(variables.activityId),
1418
- newData: variables.data
1419
- });
1420
- },
1421
- onError: (_, variables, context) => {
1422
- if (context == null ? void 0 : context.previousData)
1423
- queryClient.setQueryData(scoreQueryKeys.byId(variables.activityId), context.previousData);
1424
- },
1425
- onSettled: (_, err, variables) => {
1426
- queryClient.invalidateQueries({
1427
- queryKey: scoreQueryKeys.byId(variables.activityId)
1428
- });
1429
- }
1430
- });
1431
- return {
1432
- mutationUpdateScore: mutation
1433
- };
1434
- }
1435
- function useUpdateCardScore({
1436
- isAssignment,
1437
- activityId,
1438
- userId,
1439
- cardIds,
1440
- weights
1441
- }) {
1442
- const { queryClient } = useSpeakableApi();
1443
- const queryKey = scoreQueryKeys.byId(activityId);
1444
- const mutation = (0, import_react_query2.useMutation)({
1445
- mutationFn: async ({ cardId, cardScore }) => {
1446
- const previousScores = queryClient.getQueryData(queryKey);
1447
- const { progress, score, newScoreUpdated, updatedCardScore } = getScoreUpdated({
1448
- previousScores: previousScores != null ? previousScores : {},
1449
- cardId,
1450
- cardScore,
1451
- cardIds,
1452
- weights
1453
- });
1454
- await updateCardScore({
1455
- userId,
1456
- cardId,
1457
- isAssignment,
1458
- activityId,
1459
- updates: {
1460
- cardScore: updatedCardScore,
1461
- progress,
1462
- score
1463
- }
1464
- });
1465
- return { cardId, scoresUpdated: newScoreUpdated };
1466
- },
1467
- onMutate: ({ cardId, cardScore }) => {
1468
- const previousData = queryClient.getQueryData(queryKey);
1469
- queryClient.setQueryData(queryKey, (previousScore) => {
1470
- const updates = handleOptimisticScore({
1471
- score: previousScore,
1472
- cardId,
1473
- cardScore,
1474
- cardIds,
1475
- weights
1476
- });
1477
- return {
1478
- ...previousScore,
1479
- ...updates
1480
- };
1481
- });
1482
- return { previousData };
1483
- },
1484
- onError: (error, variables, context) => {
1485
- console.log("Error updating card score:", error.message);
1486
- if (context == null ? void 0 : context.previousData) {
1487
- queryClient.setQueryData(queryKey, context.previousData);
1488
- }
1489
- },
1490
- onSettled: () => {
1491
- queryClient.invalidateQueries({
1492
- queryKey
1493
- });
1494
- }
1495
- });
1496
- return {
1497
- mutationUpdateCardScore: mutation
1498
- };
1499
- }
1500
- var getScoreUpdated = ({
1501
- cardId,
1502
- cardScore,
1503
- previousScores,
1504
- cardIds,
1505
- weights
1506
- }) => {
1507
- var _a, _b;
1508
- const previousCard = (_a = previousScores.cards) == null ? void 0 : _a[cardId];
1509
- const newCardScore = {
1510
- ...previousCard != null ? previousCard : {},
1511
- ...cardScore
1512
- };
1513
- const newScores = {
1514
- ...previousScores,
1515
- cards: {
1516
- ...(_b = previousScores.cards) != null ? _b : {},
1517
- [cardId]: newCardScore
1518
- }
1519
- };
1520
- const { score, progress } = calculateScoreAndProgress_default(newScores, cardIds, weights);
1521
- return {
1522
- newScoreUpdated: newScores,
1523
- updatedCardScore: cardScore,
1524
- score,
1525
- progress
1526
- };
1527
- };
1528
- var handleOptimisticScore = ({
1529
- score,
1530
- cardId,
1531
- cardScore,
1532
- cardIds,
1533
- weights
1534
- }) => {
1535
- var _a;
1536
- let cards = { ...(_a = score == null ? void 0 : score.cards) != null ? _a : {} };
1537
- cards = {
1538
- ...cards,
1539
- [cardId]: {
1540
- ...cards[cardId],
1541
- ...cardScore
1542
- }
1543
- };
1544
- const { score: scoreValue, progress } = calculateScoreAndProgress_default(
1545
- // @ts-ignore
1546
- {
1547
- ...score != null ? score : {},
1548
- cards
1549
- },
1550
- cardIds,
1551
- weights
1552
- );
1553
- return { cards, score: scoreValue, progress };
1554
- };
1555
- function useClearScore() {
1556
- const { queryClient } = useSpeakableApi();
1557
- const mutation = (0, import_react_query2.useMutation)({
1558
- mutationFn: clearScore,
1559
- onError: (error) => {
1560
- console.log("Error clearing score:", error.message);
1561
- },
1562
- onSettled: (result) => {
1563
- var _a;
1564
- queryClient.invalidateQueries({
1565
- queryKey: scoreQueryKeys.byId((_a = result == null ? void 0 : result.activityId) != null ? _a : "")
1566
- });
1567
- }
1568
- });
1569
- return {
1570
- mutationClearScore: mutation
1571
- };
1572
- }
1573
- function useClearScoreV2() {
1574
- const { queryClient } = useSpeakableApi();
1575
- const mutation = (0, import_react_query2.useMutation)({
1576
- mutationFn: clearScoreV2,
1577
- onError: (error) => {
1578
- console.log("Error clearing score V2:", error.message);
1579
- },
1580
- onSettled: (result) => {
1581
- var _a;
1582
- queryClient.invalidateQueries({
1583
- queryKey: scoreQueryKeys.byId((_a = result == null ? void 0 : result.activityId) != null ? _a : "")
1584
- });
1585
- }
1586
- });
1587
- return {
1588
- mutationClearScore: mutation
1589
- };
1590
- }
1591
- function useSubmitAssignmentScore({
1592
- onAssignmentSubmitted,
1593
- studentName
1594
- }) {
1595
- const { queryClient } = useSpeakableApi();
1596
- const { hasGoogleClassroomGradePassback } = usePermissions_default();
1597
- const { submitAssignmentToGoogleClassroom } = useGoogleClassroom();
1598
- const { createNotification: createNotification2 } = useCreateNotification();
1599
- const mutation = (0, import_react_query2.useMutation)({
1600
- mutationFn: async ({
1601
- assignment,
1602
- userId,
1603
- cardIds,
1604
- weights,
1605
- scores,
1606
- status
1607
- }) => {
1608
- try {
1609
- const scoreUpdated = await submitAssignmentScore({
1610
- assignment,
1611
- userId,
1612
- cardIds,
1613
- weights,
1614
- status,
1615
- studentName
1616
- });
1617
- if (assignment.courseWorkId != null && !assignment.isAssessment && hasGoogleClassroomGradePassback) {
1618
- await submitAssignmentToGoogleClassroom({
1619
- assignment,
1620
- scores
1621
- });
1622
- }
1623
- if (assignment.isAssessment) {
1624
- createNotification2(SpeakableNotificationTypes.ASSESSMENT_SUBMITTED, assignment);
1625
- }
1626
- if (assignment == null ? void 0 : assignment.id) {
1627
- logSubmitAssignment({
1628
- courseId: assignment == null ? void 0 : assignment.courseId
1629
- });
1630
- }
1631
- onAssignmentSubmitted(assignment.id);
1632
- queryClient.setQueryData(scoreQueryKeys.byId(assignment.id), {
1633
- ...scores,
1634
- ...scoreUpdated.fieldsUpdated
1635
- });
1636
- return {
1637
- success: true,
1638
- message: "Score submitted successfully"
1639
- };
1640
- } catch (error) {
1641
- return {
1642
- success: false,
1643
- error
1644
- };
1645
- }
1646
- }
1647
- });
1648
- return {
1649
- submitAssignmentScore: mutation.mutateAsync,
1650
- isLoading: mutation.isPending
1651
- };
1652
- }
1653
- function useSubmitPracticeScore() {
1654
- const { queryClient } = useSpeakableApi();
1655
- const mutation = (0, import_react_query2.useMutation)({
1656
- mutationFn: async ({
1657
- setId,
1658
- userId,
1659
- scores
1660
- }) => {
1661
- try {
1662
- await submitPracticeScore({
1663
- setId,
1664
- userId,
1665
- scores
1666
- });
1667
- queryClient.invalidateQueries({
1668
- queryKey: scoreQueryKeys.byId(setId)
1669
- });
1670
- return {
1671
- success: true,
1672
- message: "Score submitted successfully"
1673
- };
1674
- } catch (error) {
1675
- return {
1676
- success: false,
1677
- error
1678
- };
1679
- }
1680
- }
1681
- });
1682
- return {
1683
- submitPracticeScore: mutation.mutateAsync,
1684
- isLoading: mutation.isPending
1685
- };
1686
- }
1687
897
 
1688
898
  // src/domains/cards/card.hooks.ts
1689
899
  var import_react_query3 = require("@tanstack/react-query");
1690
900
  var import_react2 = require("react");
1691
901
 
1692
- // src/domains/cards/card.model.ts
1693
- var ActivityPageType = /* @__PURE__ */ ((ActivityPageType2) => {
1694
- ActivityPageType2["READ_REPEAT"] = "READ_REPEAT";
1695
- ActivityPageType2["READ_RESPOND"] = "READ_RESPOND";
1696
- ActivityPageType2["FREE_RESPONSE"] = "FREE_RESPONSE";
1697
- ActivityPageType2["REPEAT"] = "REPEAT";
1698
- ActivityPageType2["RESPOND"] = "RESPOND";
1699
- ActivityPageType2["RESPOND_WRITE"] = "RESPOND_WRITE";
1700
- ActivityPageType2["MULTIPLE_CHOICE"] = "MULTIPLE_CHOICE";
1701
- ActivityPageType2["MEDIA_PAGE"] = "MEDIA_PAGE";
1702
- ActivityPageType2["SHORT_ANSWER"] = "SHORT_ANSWER";
1703
- return ActivityPageType2;
1704
- })(ActivityPageType || {});
1705
- var RESPOND_PAGE_ACTIVITY_TYPES = [
1706
- "READ_RESPOND" /* READ_RESPOND */,
1707
- "RESPOND" /* RESPOND */,
1708
- "RESPOND_WRITE" /* RESPOND_WRITE */,
1709
- "FREE_RESPONSE" /* FREE_RESPONSE */
1710
- ];
1711
- var MULTIPLE_CHOICE_PAGE_ACTIVITY_TYPES = ["MULTIPLE_CHOICE" /* MULTIPLE_CHOICE */];
1712
- var REPEAT_PAGE_ACTIVITY_TYPES = ["READ_REPEAT" /* READ_REPEAT */, "REPEAT" /* REPEAT */];
1713
- var RESPOND_WRITE_PAGE_ACTIVITY_TYPES = [
1714
- "RESPOND_WRITE" /* RESPOND_WRITE */,
1715
- "FREE_RESPONSE" /* FREE_RESPONSE */
1716
- ];
1717
- var RESPOND_AUDIO_PAGE_ACTIVITY_TYPES = [
1718
- "RESPOND" /* RESPOND */,
1719
- "READ_RESPOND" /* READ_RESPOND */
1720
- ];
1721
-
1722
902
  // src/domains/cards/card.constants.ts
1723
- var FeedbackTypesCard = /* @__PURE__ */ ((FeedbackTypesCard2) => {
1724
- FeedbackTypesCard2["SuggestedResponse"] = "suggested_response";
1725
- FeedbackTypesCard2["Wida"] = "wida";
1726
- FeedbackTypesCard2["GrammarInsights"] = "grammar_insights";
1727
- FeedbackTypesCard2["Actfl"] = "actfl";
1728
- FeedbackTypesCard2["ProficiencyLevel"] = "proficiency_level";
1729
- return FeedbackTypesCard2;
1730
- })(FeedbackTypesCard || {});
1731
- var LeniencyCard = /* @__PURE__ */ ((LeniencyCard2) => {
1732
- LeniencyCard2["CONFIDENCE"] = "confidence";
1733
- LeniencyCard2["EASY"] = "easy";
1734
- LeniencyCard2["NORMAL"] = "normal";
1735
- LeniencyCard2["HARD"] = "hard";
1736
- return LeniencyCard2;
1737
- })(LeniencyCard || {});
1738
- var LENIENCY_OPTIONS = [
1739
- {
1740
- label: "Build Confidence - most lenient",
1741
- value: "confidence" /* CONFIDENCE */
1742
- },
1743
- {
1744
- label: "Very Lenient",
1745
- value: "easy" /* EASY */
1746
- },
1747
- {
1748
- label: "Normal",
1749
- value: "normal" /* NORMAL */
1750
- },
1751
- {
1752
- label: "No leniency - most strict",
1753
- value: "hard" /* HARD */
1754
- }
1755
- ];
1756
- var STUDENT_LEVELS_OPTIONS = [
1757
- {
1758
- label: "Beginner",
1759
- description: "Beginner Level: Just starting out. Can say a few basic words and phrases.",
1760
- value: "beginner"
1761
- },
1762
- {
1763
- label: "Elementary",
1764
- description: "Elementary Level: Can understand simple sentences and have very basic conversations.",
1765
- value: "elementary"
1766
- },
1767
- {
1768
- label: "Intermediate",
1769
- description: "Intermediate Level: Can talk about everyday topics and handle common situations.",
1770
- value: "intermediate"
1771
- },
1772
- {
1773
- label: "Advanced",
1774
- description: "Advanced Level: Can speak and understand with ease, and explain ideas clearly.",
1775
- value: "advanced"
1776
- },
1777
- {
1778
- label: "Fluent",
1779
- description: "Fluent Level: Speaks naturally and easily. Can use the language in work or school settings.",
1780
- value: "fluent"
1781
- },
1782
- {
1783
- label: "Native-like",
1784
- description: "Native-like Level: Understands and speaks like a native. Can discuss complex ideas accurately.",
1785
- value: "nativeLike"
1786
- }
1787
- ];
1788
- var BASE_RESPOND_FIELD_VALUES = {
1789
- title: "",
1790
- allowRetries: true,
1791
- respondTime: 180,
1792
- maxCharacters: 1e3
1793
- };
1794
- var BASE_REPEAT_FIELD_VALUES = {
1795
- repeat: 1
1796
- };
1797
- var BASE_MULTIPLE_CHOICE_FIELD_VALUES = {
1798
- MCQType: "single",
1799
- answer: ["A"],
1800
- choices: [
1801
- { option: "A", value: "Option A" },
1802
- { option: "B", value: "Option B" },
1803
- { option: "C", value: "Option C" }
1804
- ]
1805
- };
1806
- var VerificationCardStatus = /* @__PURE__ */ ((VerificationCardStatus2) => {
1807
- VerificationCardStatus2["VERIFIED"] = "VERIFIED";
1808
- VerificationCardStatus2["WARNING"] = "WARNING";
1809
- VerificationCardStatus2["NOT_RECOMMENDED"] = "NOT_RECOMMENDED";
1810
- VerificationCardStatus2["NOT_WORKING"] = "NOT_WORKING";
1811
- VerificationCardStatus2["NOT_CHECKED"] = "NOT_CHECKED";
1812
- return VerificationCardStatus2;
1813
- })(VerificationCardStatus || {});
1814
903
  var CARDS_COLLECTION = "flashcards";
1815
904
  var refsCardsFiresotre = {
1816
905
  allCards: CARDS_COLLECTION,
@@ -1857,13 +946,6 @@ var getWordHash = (word, language) => {
1857
946
  console.log("wordHash core library", wordHash);
1858
947
  return wordHash;
1859
948
  };
1860
- function getPhraseLength(phrase, input) {
1861
- if (Array.isArray(phrase) && phrase.includes(input)) {
1862
- return phrase[phrase.indexOf(input)].split(" ").length;
1863
- } else {
1864
- return phrase ? phrase.split(" ").length : 0;
1865
- }
1866
- }
1867
949
 
1868
950
  // src/domains/cards/services/get-card-verification-status.service.ts
1869
951
  var charactarLanguages = ["zh", "ja", "ko"];
@@ -1934,81 +1016,6 @@ async function _createCards({ cards }) {
1934
1016
  }
1935
1017
  var createCards = withErrorHandler(_createCards, "createCards");
1936
1018
 
1937
- // src/domains/cards/card.hooks.ts
1938
- var cardsQueryKeys = {
1939
- all: ["cards"],
1940
- one: (params) => [...cardsQueryKeys.all, params.cardId]
1941
- };
1942
- function useCards({
1943
- cardIds,
1944
- enabled = true,
1945
- asObject
1946
- }) {
1947
- const queries = (0, import_react_query3.useQueries)({
1948
- queries: cardIds.map((cardId) => ({
1949
- enabled: enabled && cardIds.length > 0,
1950
- queryKey: cardsQueryKeys.one({
1951
- cardId
1952
- }),
1953
- queryFn: () => getCard({ cardId })
1954
- }))
1955
- });
1956
- const cards = queries.map((query2) => query2.data).filter(Boolean);
1957
- const cardsObject = (0, import_react2.useMemo)(() => {
1958
- if (!asObject) return null;
1959
- return cards.reduce((acc, card) => {
1960
- acc[card.id] = card;
1961
- return acc;
1962
- }, {});
1963
- }, [asObject, cards]);
1964
- return {
1965
- cards,
1966
- cardsObject,
1967
- cardsQueries: queries
1968
- };
1969
- }
1970
- function useCreateCard() {
1971
- const { queryClient } = useSpeakableApi();
1972
- const mutationCreateCard = (0, import_react_query3.useMutation)({
1973
- mutationFn: createCard,
1974
- onSuccess: (cardCreated) => {
1975
- queryClient.invalidateQueries({ queryKey: cardsQueryKeys.one({ cardId: cardCreated.id }) });
1976
- }
1977
- });
1978
- return {
1979
- mutationCreateCard
1980
- };
1981
- }
1982
- function useCreateCards() {
1983
- const mutationCreateCards = (0, import_react_query3.useMutation)({
1984
- mutationFn: createCards
1985
- });
1986
- return {
1987
- mutationCreateCards
1988
- };
1989
- }
1990
- function getCardFromCache({
1991
- cardId,
1992
- queryClient
1993
- }) {
1994
- return queryClient.getQueryData(cardsQueryKeys.one({ cardId }));
1995
- }
1996
- function updateCardInCache({
1997
- cardId,
1998
- card,
1999
- queryClient
2000
- }) {
2001
- queryClient.setQueryData(cardsQueryKeys.one({ cardId }), card);
2002
- }
2003
- function useGetCard({ cardId, enabled = true }) {
2004
- const query2 = (0, import_react_query3.useQuery)({
2005
- queryKey: cardsQueryKeys.one({ cardId }),
2006
- queryFn: () => getCard({ cardId }),
2007
- enabled: enabled && !!cardId
2008
- });
2009
- return query2;
2010
- }
2011
-
2012
1019
  // src/domains/cards/card.repo.ts
2013
1020
  var createCardRepo = () => {
2014
1021
  return {
@@ -2018,177 +1025,6 @@ var createCardRepo = () => {
2018
1025
  };
2019
1026
  };
2020
1027
 
2021
- // src/domains/cards/utils/check-page-type.ts
2022
- function checkIsRepeatPage(cardType) {
2023
- if (cardType === void 0) return false;
2024
- return REPEAT_PAGE_ACTIVITY_TYPES.includes(cardType);
2025
- }
2026
- function checkIsMCPage(cardType) {
2027
- if (cardType === void 0) return false;
2028
- return MULTIPLE_CHOICE_PAGE_ACTIVITY_TYPES.includes(cardType);
2029
- }
2030
- function checkIsRespondPage(cardType) {
2031
- if (cardType === void 0) return false;
2032
- return RESPOND_PAGE_ACTIVITY_TYPES.includes(cardType);
2033
- }
2034
- function checkIsRespondWrittenPage(cardType) {
2035
- if (cardType === void 0) return false;
2036
- return RESPOND_WRITE_PAGE_ACTIVITY_TYPES.includes(cardType);
2037
- }
2038
- function checkIsRespondAudioPage(cardType) {
2039
- if (cardType === void 0) return false;
2040
- return RESPOND_AUDIO_PAGE_ACTIVITY_TYPES.includes(cardType);
2041
- }
2042
- var checkIsMediaPage = (cardType) => {
2043
- if (cardType === void 0) return false;
2044
- return cardType === "MEDIA_PAGE" /* MEDIA_PAGE */;
2045
- };
2046
- var checkIsShortAnswerPage = (cardType) => {
2047
- if (cardType === void 0) return false;
2048
- return cardType === "SHORT_ANSWER" /* SHORT_ANSWER */;
2049
- };
2050
- var checkTypePageActivity = (cardType) => {
2051
- const isRespondAudio = checkIsRespondAudioPage(cardType);
2052
- const isRespondWritten = checkIsRespondWrittenPage(cardType);
2053
- const isRespond = checkIsRespondPage(cardType);
2054
- const isMC = checkIsMCPage(cardType);
2055
- const isRepeat = checkIsRepeatPage(cardType);
2056
- const isMediaPage = checkIsMediaPage(cardType);
2057
- const isShortAnswer = checkIsShortAnswerPage(cardType);
2058
- const isNoOneOfThem = !isRespond && !isMC && !isRepeat && !isMediaPage && !isShortAnswer;
2059
- if (isNoOneOfThem) {
2060
- return {
2061
- isRespondAudio: false,
2062
- isRespondWritten: false,
2063
- isRespond: false,
2064
- isMC: false,
2065
- isRepeat: true,
2066
- isMediaPage: false,
2067
- isShortAnswer: false,
2068
- hasSomeType: false
2069
- };
2070
- }
2071
- return {
2072
- isRespondAudio,
2073
- isRespondWritten,
2074
- isRespond,
2075
- isMC,
2076
- isRepeat,
2077
- isMediaPage,
2078
- isShortAnswer,
2079
- hasSomeType: true
2080
- };
2081
- };
2082
-
2083
- // src/domains/cards/utils/get-page-prompt.ts
2084
- function extractTextFromRichText(richText) {
2085
- if (!richText) return "";
2086
- return richText.replace(/<[^>]*>/g, "").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").trim();
2087
- }
2088
- function getPagePrompt(card) {
2089
- if (!card) return { has: false, text: "", rich_text: "", isTextEqualToRichText: false };
2090
- const { isMC, isRepeat, isRespond, isShortAnswer } = checkTypePageActivity(card == null ? void 0 : card.type);
2091
- const hidePrompt = (card == null ? void 0 : card.hidePrompt) === true;
2092
- const createReturnObject = (text, richText) => {
2093
- const plainText = text || "";
2094
- const richTextPlain = extractTextFromRichText(richText);
2095
- return {
2096
- has: true,
2097
- text: plainText,
2098
- rich_text: richText || "",
2099
- isTextEqualToRichText: plainText.trim() === richTextPlain.trim()
2100
- };
2101
- };
2102
- if (isRepeat) {
2103
- return createReturnObject(card == null ? void 0 : card.target_text, card == null ? void 0 : card.rich_text);
2104
- }
2105
- if (isRespond && !hidePrompt) {
2106
- return createReturnObject(card == null ? void 0 : card.prompt, card == null ? void 0 : card.rich_text);
2107
- }
2108
- if (isMC) {
2109
- return createReturnObject(card == null ? void 0 : card.question, card == null ? void 0 : card.rich_text);
2110
- }
2111
- if (isShortAnswer && !hidePrompt) {
2112
- return createReturnObject(card == null ? void 0 : card.prompt, card == null ? void 0 : card.rich_text);
2113
- }
2114
- return {
2115
- has: false,
2116
- text: "",
2117
- rich_text: "",
2118
- isTextEqualToRichText: false
2119
- };
2120
- }
2121
-
2122
- // src/domains/cards/utils/get-completed-pages.ts
2123
- var getTotalCompletedCards = (pageScores) => {
2124
- return Object.values(pageScores != null ? pageScores : {}).reduce((acc, cardScore) => {
2125
- var _a, _b;
2126
- if (((_b = (_a = cardScore.completed) != null ? _a : cardScore.score) != null ? _b : cardScore.score === 0) && !cardScore.media_area_opened) {
2127
- acc++;
2128
- }
2129
- return acc;
2130
- }, 0);
2131
- };
2132
-
2133
- // src/domains/cards/utils/get-label-page.ts
2134
- var labels = {
2135
- repeat: {
2136
- short: "Repeat",
2137
- long: "Listen & Repeat"
2138
- },
2139
- mc: {
2140
- short: "Multiple Choice",
2141
- long: "Multiple Choice"
2142
- },
2143
- mediaPage: {
2144
- short: "Media Page",
2145
- long: "Media Page"
2146
- },
2147
- shortAnswer: {
2148
- short: "Short Answer",
2149
- long: "Short Answer"
2150
- },
2151
- respondWritten: {
2152
- short: "Open Response",
2153
- long: "Written Open Response"
2154
- },
2155
- respondAudio: {
2156
- short: "Open Response",
2157
- long: "Spoken Open Response"
2158
- }
2159
- };
2160
- var getLabelPage = (pageType) => {
2161
- if (!pageType) {
2162
- return {
2163
- short: "",
2164
- long: ""
2165
- };
2166
- }
2167
- const { isRepeat, isMC, isMediaPage, isShortAnswer, isRespondWritten, isRespondAudio } = checkTypePageActivity(pageType);
2168
- if (isRepeat) {
2169
- return labels.repeat;
2170
- }
2171
- if (isMC) {
2172
- return labels.mc;
2173
- }
2174
- if (isMediaPage) {
2175
- return labels.mediaPage;
2176
- }
2177
- if (isShortAnswer) {
2178
- return labels.shortAnswer;
2179
- }
2180
- if (isRespondWritten) {
2181
- return labels.respondWritten;
2182
- }
2183
- if (isRespondAudio) {
2184
- return labels.respondAudio;
2185
- }
2186
- return {
2187
- short: "",
2188
- long: ""
2189
- };
2190
- };
2191
-
2192
1028
  // src/domains/sets/set.hooks.ts
2193
1029
  var import_react_query4 = require("@tanstack/react-query");
2194
1030
 
@@ -2206,1191 +1042,6 @@ async function _getSet({ setId }) {
2206
1042
  }
2207
1043
  var getSet = withErrorHandler(_getSet, "getSet");
2208
1044
 
2209
- // src/domains/sets/set.hooks.ts
2210
- var setsQueryKeys = {
2211
- all: ["sets"],
2212
- one: (params) => [...setsQueryKeys.all, params.setId]
2213
- };
2214
- var useSet = ({ setId, enabled }) => {
2215
- return (0, import_react_query4.useQuery)({
2216
- queryKey: setsQueryKeys.one({ setId }),
2217
- queryFn: () => getSet({ setId }),
2218
- enabled: setId !== void 0 && setId !== "" && enabled
2219
- });
2220
- };
2221
- function getSetFromCache({
2222
- setId,
2223
- queryClient
2224
- }) {
2225
- if (!setId) return null;
2226
- return queryClient.getQueryData(setsQueryKeys.one({ setId }));
2227
- }
2228
- function updateSetInCache({
2229
- set,
2230
- queryClient
2231
- }) {
2232
- const { id, ...setData } = set;
2233
- queryClient.setQueryData(setsQueryKeys.one({ setId: id }), setData);
2234
- }
2235
-
2236
- // src/domains/sets/set.repo.ts
2237
- var createSetRepo = () => {
2238
- return {
2239
- getSet
2240
- };
2241
- };
2242
-
2243
- // src/constants/all-langs.json
2244
- var all_langs_default = {
2245
- af: "Afrikaans",
2246
- sq: "Albanian",
2247
- am: "Amharic",
2248
- ar: "Arabic",
2249
- hy: "Armenian",
2250
- az: "Azerbaijani",
2251
- eu: "Basque",
2252
- be: "Belarusian",
2253
- bn: "Bengali",
2254
- bs: "Bosnian",
2255
- bg: "Bulgarian",
2256
- ca: "Catalan",
2257
- ceb: "Cebuano",
2258
- zh: "Chinese",
2259
- co: "Corsican",
2260
- hr: "Croatian",
2261
- cs: "Czech",
2262
- da: "Danish",
2263
- nl: "Dutch",
2264
- en: "English",
2265
- eo: "Esperanto",
2266
- et: "Estonian",
2267
- fi: "Finnish",
2268
- fr: "French",
2269
- fy: "Frisian",
2270
- gl: "Galician",
2271
- ka: "Georgian",
2272
- de: "German",
2273
- el: "Greek",
2274
- gu: "Gujarati",
2275
- ht: "Haitian Creole",
2276
- ha: "Hausa",
2277
- haw: "Hawaiian",
2278
- he: "Hebrew",
2279
- hi: "Hindi",
2280
- hmn: "Hmong",
2281
- hu: "Hungarian",
2282
- is: "Icelandic",
2283
- ig: "Igbo",
2284
- id: "Indonesian",
2285
- ga: "Irish",
2286
- it: "Italian",
2287
- ja: "Japanese",
2288
- jv: "Javanese",
2289
- kn: "Kannada",
2290
- kk: "Kazakh",
2291
- km: "Khmer",
2292
- ko: "Korean",
2293
- ku: "Kurdish",
2294
- ky: "Kyrgyz",
2295
- lo: "Lao",
2296
- la: "Latin",
2297
- lv: "Latvian",
2298
- lt: "Lithuanian",
2299
- lb: "Luxembourgish",
2300
- mk: "Macedonian",
2301
- mg: "Malagasy",
2302
- ms: "Malay",
2303
- ml: "Malayalam",
2304
- mt: "Maltese",
2305
- mi: "Maori",
2306
- mr: "Marathi",
2307
- mn: "Mongolian",
2308
- my: "Myanmar (Burmese)",
2309
- ne: "Nepali",
2310
- no: "Norwegian",
2311
- ny: "Nyanja (Chichewa)",
2312
- ps: "Pashto",
2313
- fa: "Persian",
2314
- pl: "Polish",
2315
- pt: "Portuguese",
2316
- pa: "Punjabi",
2317
- ro: "Romanian",
2318
- ru: "Russian",
2319
- sm: "Samoan",
2320
- gd: "Scots Gaelic",
2321
- sr: "Serbian",
2322
- st: "Sesotho",
2323
- sn: "Shona",
2324
- sd: "Sindhi",
2325
- si: "Sinhala (Sinhalese)",
2326
- sk: "Slovak",
2327
- sl: "Slovenian",
2328
- so: "Somali",
2329
- es: "Spanish",
2330
- su: "Sundanese",
2331
- sw: "Swahili",
2332
- sv: "Swedish",
2333
- tl: "Tagalog (Filipino)",
2334
- tg: "Tajik",
2335
- ta: "Tamil",
2336
- te: "Telugu",
2337
- th: "Thai",
2338
- tr: "Turkish",
2339
- uk: "Ukrainian",
2340
- ur: "Urdu",
2341
- uz: "Uzbek",
2342
- vi: "Vietnamese",
2343
- cy: "Welsh",
2344
- xh: "Xhosa",
2345
- yi: "Yiddish",
2346
- yo: "Yoruba",
2347
- zu: "Zulu"
2348
- };
2349
-
2350
- // src/utils/ai/get-respond-card-tool.ts
2351
- var getRespondCardTool = ({
2352
- language,
2353
- standard = "actfl"
2354
- }) => {
2355
- const lang = all_langs_default[language] || "English";
2356
- const tool = {
2357
- tool_choice: {
2358
- type: "function",
2359
- function: { name: "get_feedback" }
2360
- },
2361
- tools: [
2362
- {
2363
- type: "function",
2364
- function: {
2365
- name: "get_feedback",
2366
- description: "Get feedback on a student's response",
2367
- parameters: {
2368
- type: "object",
2369
- required: [
2370
- "success",
2371
- "score",
2372
- "score_justification",
2373
- "errors",
2374
- "improvedResponse",
2375
- "compliments"
2376
- ],
2377
- properties: {
2378
- success: {
2379
- type: "boolean",
2380
- 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."
2381
- },
2382
- errors: {
2383
- type: "array",
2384
- items: {
2385
- type: "object",
2386
- required: ["error", "grammar_error_type", "correction", "justification"],
2387
- properties: {
2388
- error: {
2389
- type: "string",
2390
- description: "The grammatical error in the student's response."
2391
- },
2392
- correction: {
2393
- type: "string",
2394
- description: "The suggested correction to the error"
2395
- },
2396
- justification: {
2397
- type: "string",
2398
- description: `An explanation of the rationale behind the suggested correction. WRITE THIS IN ${lang}!`
2399
- },
2400
- grammar_error_type: {
2401
- type: "string",
2402
- enum: [
2403
- "subjVerbAgree",
2404
- "tenseErrors",
2405
- "articleMisuse",
2406
- "prepositionErrors",
2407
- "adjNounAgree",
2408
- "pronounErrors",
2409
- "wordOrder",
2410
- "verbConjugation",
2411
- "pluralization",
2412
- "negationErrors",
2413
- "modalVerbMisuse",
2414
- "relativeClause",
2415
- "auxiliaryVerb",
2416
- "complexSentenceAgreement",
2417
- "idiomaticExpression",
2418
- "registerInconsistency",
2419
- "voiceMisuse"
2420
- ],
2421
- 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"
2422
- }
2423
- }
2424
- },
2425
- 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."
2426
- },
2427
- compliments: {
2428
- type: "array",
2429
- items: {
2430
- type: "string"
2431
- },
2432
- description: `An array of strings, each representing something the student did well. Each string should be WRITTEN IN ${lang}!`
2433
- },
2434
- improvedResponse: {
2435
- type: "string",
2436
- description: "An improved response with proper grammar and more detail, if applicable."
2437
- },
2438
- score: {
2439
- type: "number",
2440
- description: "A score between 0 and 100, reflecting the overall quality of the response"
2441
- },
2442
- score_justification: {
2443
- type: "string",
2444
- description: "An explanation of the rationale behind the assigned score, considering both accuracy and fluency"
2445
- }
2446
- }
2447
- }
2448
- }
2449
- }
2450
- ]
2451
- };
2452
- if (standard === "wida") {
2453
- const wida_level = {
2454
- type: "number",
2455
- enum: [1, 2, 3, 4, 5, 6],
2456
- 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
2457
-
2458
- 1 - Entering
2459
- 2 - Emerging
2460
- 3 - Developing
2461
- 4 - Expanding
2462
- 5 - Bridging
2463
- 6 - Reaching
2464
-
2465
- 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.
2466
- `
2467
- };
2468
- const wida_justification = {
2469
- type: "string",
2470
- description: `An explanation of the rationale behind the assigned WIDA level of the response, considering both accuracy and fluency. WRITE THIS IN ENGLISH!`
2471
- };
2472
- tool.tools[0].function.parameters.required.push("wida_level");
2473
- tool.tools[0].function.parameters.required.push("wida_justification");
2474
- tool.tools[0].function.parameters.properties.wida_level = wida_level;
2475
- tool.tools[0].function.parameters.properties.wida_justification = wida_justification;
2476
- } else {
2477
- const actfl_level = {
2478
- type: "string",
2479
- enum: ["NL", "NM", "NH", "IL", "IM", "IH", "AL", "AM", "AH", "S", "D"],
2480
- 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"
2481
- };
2482
- const actfl_justification = {
2483
- type: "string",
2484
- description: "An explanation of the rationale behind the assigned ACTFL level, considering both accuracy and fluency"
2485
- };
2486
- tool.tools[0].function.parameters.required.push("actfl_level");
2487
- tool.tools[0].function.parameters.required.push("actfl_justification");
2488
- tool.tools[0].function.parameters.properties.actfl_level = actfl_level;
2489
- tool.tools[0].function.parameters.properties.actfl_justification = actfl_justification;
2490
- }
2491
- return tool;
2492
- };
2493
-
2494
- // src/hooks/useActivity.ts
2495
- var import_react3 = require("react");
2496
-
2497
- // src/services/add-grading-standard.ts
2498
- var addGradingStandardLog = async (gradingStandard, userId) => {
2499
- logGradingStandardLog(gradingStandard);
2500
- const path = `users/${userId}/grading_standard_logs`;
2501
- await api.addDoc(path, gradingStandard);
2502
- };
2503
-
2504
- // src/hooks/useActivityTracker.ts
2505
- var import_uuid2 = require("uuid");
2506
- function useActivityTracker({ userId }) {
2507
- const trackActivity = async ({
2508
- activityName,
2509
- activityType,
2510
- id = (0, import_uuid2.v4)(),
2511
- language = ""
2512
- }) => {
2513
- if (userId) {
2514
- const { doc: doc2, serverTimestamp: serverTimestamp2, setDoc: setDoc2 } = api.accessHelpers();
2515
- const activityRef = doc2(`users/${userId}/activity/${id}`);
2516
- const timestamp = serverTimestamp2();
2517
- await setDoc2(activityRef, {
2518
- name: activityName,
2519
- type: activityType,
2520
- lastSeen: timestamp,
2521
- id,
2522
- language
2523
- });
2524
- }
2525
- };
2526
- return {
2527
- trackActivity
2528
- };
2529
- }
2530
-
2531
- // src/hooks/useActivity.ts
2532
- function useActivity({
2533
- id,
2534
- isAssignment,
2535
- onAssignmentSubmitted,
2536
- ltiData
2537
- }) {
2538
- var _a, _b;
2539
- const { queryClient, user } = useSpeakableApi();
2540
- const userId = user.auth.uid;
2541
- const assignmentQuery = useAssignment({
2542
- assignmentId: id,
2543
- userId,
2544
- enabled: isAssignment
2545
- });
2546
- const activeAssignment = assignmentQuery.data;
2547
- const setId = isAssignment ? (_a = activeAssignment == null ? void 0 : activeAssignment.setId) != null ? _a : "" : id;
2548
- const querySet = useSet({ setId });
2549
- const setData = querySet.data;
2550
- const assignmentContent = activeAssignment == null ? void 0 : activeAssignment.content;
2551
- const assignmentWeights = activeAssignment == null ? void 0 : activeAssignment.weights;
2552
- const setContent = setData == null ? void 0 : setData.content;
2553
- const setWeights = setData == null ? void 0 : setData.weights;
2554
- const contentCardsToUse = isAssignment ? assignmentContent != null ? assignmentContent : setContent : setContent;
2555
- const weightsToUse = isAssignment ? assignmentWeights != null ? assignmentWeights : setWeights : setWeights;
2556
- const activityId = isAssignment ? (_b = activeAssignment == null ? void 0 : activeAssignment.id) != null ? _b : "" : setId;
2557
- const { cardsObject, cardsQueries, cards } = useCards({
2558
- cardIds: contentCardsToUse != null ? contentCardsToUse : [],
2559
- enabled: querySet.isSuccess,
2560
- asObject: true
2561
- });
2562
- const scorableCardIds = (contentCardsToUse != null ? contentCardsToUse : []).filter((cardId) => {
2563
- const card = cardsObject == null ? void 0 : cardsObject[cardId];
2564
- return (card == null ? void 0 : card.type) !== "MEDIA_PAGE" /* MEDIA_PAGE */;
2565
- });
2566
- const scoreQuery = useScore({
2567
- isAssignment,
2568
- activityId: id,
2569
- userId,
2570
- courseId: activeAssignment == null ? void 0 : activeAssignment.courseId,
2571
- googleClassroomUserId: user.profile.googleClassroomUserId,
2572
- enabled: isAssignment ? assignmentQuery.isSuccess : querySet.isSuccess
2573
- });
2574
- const { mutationUpdateScore } = useUpdateScore();
2575
- const { mutationUpdateCardScore } = useUpdateCardScore({
2576
- activityId,
2577
- isAssignment,
2578
- userId,
2579
- cardIds: scorableCardIds,
2580
- weights: weightsToUse != null ? weightsToUse : {}
2581
- });
2582
- const { mutationClearScore } = useClearScore();
2583
- const { submitAssignmentScore: submitAssignmentScore2 } = useSubmitAssignmentScore({
2584
- onAssignmentSubmitted,
2585
- studentName: user.profile.displayName
2586
- });
2587
- const { submitPracticeScore: submitPracticeScore2 } = useSubmitPracticeScore();
2588
- const handleUpdateScore = (data) => {
2589
- mutationUpdateScore.mutate({
2590
- data,
2591
- isAssignment,
2592
- activityId,
2593
- userId
2594
- });
2595
- };
2596
- const handleUpdateCardScore = (cardId, cardScore) => {
2597
- mutationUpdateCardScore.mutate({ cardId, cardScore });
2598
- if (cardScore.proficiency_level) {
2599
- logGradingStandardEntry({
2600
- type: cardScore.proficiency_level.standardId,
2601
- cardId,
2602
- gradingStandard: cardScore.proficiency_level
2603
- });
2604
- } else if (cardScore.wida || cardScore.actfl) {
2605
- logGradingStandardEntry({
2606
- type: cardScore.wida ? "wida" : "actfl",
2607
- cardId,
2608
- gradingStandard: cardScore.wida || cardScore.actfl || { level: "", justification: "" }
2609
- });
2610
- }
2611
- };
2612
- const onClearScore = ({
2613
- cardId,
2614
- wasCompleted = true
2615
- }) => {
2616
- var _a2, _b2;
2617
- const currentCard = cardsObject == null ? void 0 : cardsObject[cardId];
2618
- if ((currentCard == null ? void 0 : currentCard.type) === "MULTIPLE_CHOICE" /* MULTIPLE_CHOICE */ || (currentCard == null ? void 0 : currentCard.type) === "READ_REPEAT" /* READ_REPEAT */) {
2619
- return;
2620
- }
2621
- const queryKeys = scoreQueryKeys.byId(activityId);
2622
- const activeCardScores = (_b2 = (_a2 = queryClient.getQueryData(queryKeys)) == null ? void 0 : _a2.cards) == null ? void 0 : _b2[cardId];
2623
- if (activeCardScores === void 0) return;
2624
- mutationClearScore.mutate({
2625
- isAssignment,
2626
- activityId,
2627
- cardScores: activeCardScores,
2628
- cardId,
2629
- userId
2630
- });
2631
- };
2632
- const onSubmitScore = async () => {
2633
- var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w;
2634
- try {
2635
- let results;
2636
- if (isAssignment) {
2637
- const someCardIsManualGraded = cards.some((page) => page.grading_method === "manual");
2638
- results = await submitAssignmentScore2({
2639
- assignment: {
2640
- id: (_b2 = (_a2 = assignmentQuery.data) == null ? void 0 : _a2.id) != null ? _b2 : "",
2641
- name: (_d = (_c = assignmentQuery.data) == null ? void 0 : _c.name) != null ? _d : "",
2642
- owners: (_f = (_e = assignmentQuery.data) == null ? void 0 : _e.owners) != null ? _f : [],
2643
- courseId: (_h = (_g = assignmentQuery.data) == null ? void 0 : _g.courseId) != null ? _h : "",
2644
- courseWorkId: (_j = (_i = assignmentQuery.data) == null ? void 0 : _i.courseWorkId) != null ? _j : "",
2645
- isAssessment: (_l = (_k = assignmentQuery.data) == null ? void 0 : _k.isAssessment) != null ? _l : false,
2646
- maxPoints: (_n = (_m = assignmentQuery.data) == null ? void 0 : _m.maxPoints) != null ? _n : 0
2647
- },
2648
- userId,
2649
- cardIds: scorableCardIds,
2650
- scores: scoreQuery.data,
2651
- weights: weightsToUse != null ? weightsToUse : {},
2652
- status: someCardIsManualGraded ? "PENDING_REVIEW" : "SUBMITTED"
2653
- });
2654
- if ((_o = assignmentQuery.data) == null ? void 0 : _o.ltiDeeplink) {
2655
- submitLTIScore({
2656
- maxPoints: (_p = assignmentQuery.data) == null ? void 0 : _p.maxPoints,
2657
- score: (_r = (_q = scoreQuery.data) == null ? void 0 : _q.score) != null ? _r : 0,
2658
- SERVICE_KEY: (_s = ltiData == null ? void 0 : ltiData.serviceKey) != null ? _s : "",
2659
- lineItemId: (_t = ltiData == null ? void 0 : ltiData.lineItemId) != null ? _t : "",
2660
- lti_id: (_u = ltiData == null ? void 0 : ltiData.lti_id) != null ? _u : ""
2661
- });
2662
- }
2663
- } else {
2664
- results = await submitPracticeScore2({
2665
- setId: (_w = (_v = querySet.data) == null ? void 0 : _v.id) != null ? _w : "",
2666
- userId,
2667
- scores: scoreQuery.data
2668
- });
2669
- }
2670
- return results;
2671
- } catch (error) {
2672
- return {
2673
- success: false,
2674
- error
2675
- };
2676
- }
2677
- };
2678
- const logGradingStandardEntry = ({
2679
- cardId,
2680
- gradingStandard,
2681
- type
2682
- }) => {
2683
- var _a2, _b2, _c, _d, _e, _f, _g, _h, _i;
2684
- const card = cardsObject == null ? void 0 : cardsObject[cardId];
2685
- const scoresObject = queryClient.getQueryData(scoreQueryKeys.byId(activityId));
2686
- const cardScore = (_a2 = scoresObject == null ? void 0 : scoresObject.cards) == null ? void 0 : _a2[cardId];
2687
- const serverTimestamp2 = api.helpers.serverTimestamp;
2688
- addGradingStandardLog(
2689
- {
2690
- assignmentId: (_b2 = activeAssignment == null ? void 0 : activeAssignment.id) != null ? _b2 : "",
2691
- courseId: (_c = activeAssignment == null ? void 0 : activeAssignment.courseId) != null ? _c : "",
2692
- teacherId: (_d = activeAssignment == null ? void 0 : activeAssignment.owners[0]) != null ? _d : "",
2693
- setId: (_e = setData == null ? void 0 : setData.id) != null ? _e : "",
2694
- cardId,
2695
- level: gradingStandard.level,
2696
- justification: gradingStandard.justification,
2697
- transcript: (_f = cardScore == null ? void 0 : cardScore.transcript) != null ? _f : "",
2698
- audioUrl: (_g = cardScore == null ? void 0 : cardScore.audio) != null ? _g : "",
2699
- prompt: (_h = card == null ? void 0 : card.prompt) != null ? _h : "",
2700
- responseType: (card == null ? void 0 : card.type) === "RESPOND_WRITE" /* RESPOND_WRITE */ ? "written" : "spoken",
2701
- type,
2702
- dateMade: serverTimestamp2(),
2703
- language: (_i = card == null ? void 0 : card.language) != null ? _i : ""
2704
- },
2705
- userId
2706
- );
2707
- };
2708
- (0, import_react3.useEffect)(() => {
2709
- if (isAssignment) {
2710
- logOpenAssignment({ assignmentId: id });
2711
- } else {
2712
- logOpenActivityPreview({ setId: id });
2713
- }
2714
- }, []);
2715
- useInitActivity({
2716
- assignment: activeAssignment != null ? activeAssignment : void 0,
2717
- set: setData != null ? setData : void 0,
2718
- enabled: !!setData,
2719
- userId
2720
- });
2721
- return {
2722
- set: {
2723
- data: setData,
2724
- query: querySet
2725
- },
2726
- cards: {
2727
- data: cardsObject,
2728
- query: cardsQueries,
2729
- cardsArray: cards
2730
- },
2731
- assignment: {
2732
- data: isAssignment ? activeAssignment : void 0,
2733
- query: assignmentQuery
2734
- },
2735
- scores: {
2736
- data: scoreQuery.data,
2737
- query: scoreQuery,
2738
- actions: {
2739
- update: handleUpdateScore,
2740
- clear: onClearScore,
2741
- submit: onSubmitScore,
2742
- updateCard: handleUpdateCardScore,
2743
- logGradingStandardEntry
2744
- }
2745
- }
2746
- };
2747
- }
2748
- var useInitActivity = ({
2749
- assignment,
2750
- set,
2751
- enabled,
2752
- userId
2753
- }) => {
2754
- const { trackActivity } = useActivityTracker({ userId });
2755
- const init = () => {
2756
- var _a, _b, _c, _d, _e, _f, _g;
2757
- if (!enabled) return;
2758
- if (!assignment) {
2759
- trackActivity({
2760
- activityName: (_a = set == null ? void 0 : set.name) != null ? _a : "",
2761
- activityType: "set",
2762
- id: set == null ? void 0 : set.id,
2763
- language: set == null ? void 0 : set.language
2764
- });
2765
- } else if (assignment.name) {
2766
- trackActivity({
2767
- activityName: assignment.name,
2768
- activityType: assignment.isAssessment ? "assessment" : "assignment",
2769
- id: assignment.id,
2770
- language: set == null ? void 0 : set.language
2771
- });
2772
- }
2773
- if (set == null ? void 0 : set.public) {
2774
- (_d = (_c = (_b = api).httpsCallable) == null ? void 0 : _c.call(_b, "onSetOpened")) == null ? void 0 : _d({
2775
- setId: set.id,
2776
- language: set.language
2777
- });
2778
- }
2779
- (_g = (_f = (_e = api).httpsCallable) == null ? void 0 : _f.call(_e, "updateAlgoliaIndex")) == null ? void 0 : _g({
2780
- updatePlays: true,
2781
- objectID: set == null ? void 0 : set.id
2782
- });
2783
- };
2784
- (0, import_react3.useEffect)(() => {
2785
- init();
2786
- }, [set]);
2787
- };
2788
- var submitLTIScore = async ({
2789
- maxPoints,
2790
- score,
2791
- SERVICE_KEY,
2792
- lineItemId,
2793
- lti_id
2794
- }) => {
2795
- var _a, _b, _c;
2796
- try {
2797
- if (!SERVICE_KEY || !lineItemId || !lti_id) {
2798
- throw new Error("Missing required LTI credentials");
2799
- }
2800
- const earnedPoints = score ? score / 100 * maxPoints : 0;
2801
- const { data } = await ((_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "submitLTIAssignmentScore")) == null ? void 0 : _c({
2802
- SERVICE_KEY,
2803
- scoreData: {
2804
- lineItemId,
2805
- userId: lti_id,
2806
- maxPoints,
2807
- earnedPoints
2808
- }
2809
- }));
2810
- return { success: true, data };
2811
- } catch (error) {
2812
- console.error("Failed to submit LTI score:", error);
2813
- return {
2814
- success: false,
2815
- error: error instanceof Error ? error : new Error("Unknown error occurred")
2816
- };
2817
- }
2818
- };
2819
-
2820
- // src/hooks/useCredits.ts
2821
- var import_react_query5 = require("@tanstack/react-query");
2822
- var creditQueryKeys = {
2823
- userCredits: (uid) => ["userCredits", uid]
2824
- };
2825
- var useUserCredits = () => {
2826
- const { user } = useSpeakableApi();
2827
- const email = user.auth.email;
2828
- const uid = user.auth.uid;
2829
- const query2 = (0, import_react_query5.useQuery)({
2830
- queryKey: creditQueryKeys.userCredits(uid),
2831
- queryFn: () => fetchUserCredits({ uid, email }),
2832
- enabled: !!uid,
2833
- refetchInterval: 1e3 * 60 * 5
2834
- });
2835
- return {
2836
- ...query2
2837
- };
2838
- };
2839
- var fetchUserCredits = async ({ uid, email }) => {
2840
- if (!uid) {
2841
- throw new Error("User ID is required");
2842
- }
2843
- const contractSnap = await api.getDoc(`creditContracts/${uid}`);
2844
- if (contractSnap.data == null) {
2845
- return {
2846
- id: uid,
2847
- userId: uid,
2848
- email,
2849
- effectivePlanId: "free_tier",
2850
- status: "inactive",
2851
- isUnlimited: false,
2852
- creditsAvailable: 100,
2853
- creditsAllocatedThisPeriod: 100,
2854
- topOffCreditsAvailable: 0,
2855
- topOffCreditsTotal: 0,
2856
- allocationSource: "free_tier",
2857
- sourceDetails: {},
2858
- periodStart: null,
2859
- periodEnd: null,
2860
- planTermEndTimestamp: null,
2861
- ownerType: "individual",
2862
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2863
- lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
2864
- };
2865
- }
2866
- const contractData = contractSnap.data;
2867
- const monthlyCredits = (contractData == null ? void 0 : contractData.creditsAvailable) || 0;
2868
- const topOffCredits = (contractData == null ? void 0 : contractData.topOffCreditsAvailable) || 0;
2869
- const totalCredits = monthlyCredits + topOffCredits;
2870
- return {
2871
- id: contractSnap.id,
2872
- ...contractData,
2873
- // Add computed total for convenience
2874
- totalCreditsAvailable: totalCredits
2875
- };
2876
- };
2877
-
2878
- // src/hooks/useOrganizationAccess.ts
2879
- var import_react_query6 = require("@tanstack/react-query");
2880
- var useOrganizationAccess = () => {
2881
- const { user } = useSpeakableApi();
2882
- const email = user.auth.email;
2883
- const query2 = (0, import_react_query6.useQuery)({
2884
- queryKey: ["organizationAccess", email],
2885
- queryFn: async () => {
2886
- if (!email) {
2887
- return {
2888
- hasUnlimitedAccess: false,
2889
- subscriptionId: null,
2890
- organizationId: null,
2891
- organizationName: null,
2892
- subscriptionEndDate: null,
2893
- accessType: "individual"
2894
- };
2895
- }
2896
- return getOrganizationAccess(email);
2897
- },
2898
- enabled: !!email,
2899
- // Only run query if we have a user email
2900
- staleTime: 5 * 60 * 1e3,
2901
- // Consider data fresh for 5 minutes
2902
- gcTime: 10 * 60 * 1e3,
2903
- // Keep in cache for 10 minutes
2904
- retry: 2
2905
- // Retry failed requests twice
2906
- });
2907
- return {
2908
- ...query2
2909
- };
2910
- };
2911
- var getOrganizationAccess = async (email) => {
2912
- const { limit: limit2, where: where2 } = api.accessQueryConstraints();
2913
- try {
2914
- const organizationSnapshot = await api.getDocs(
2915
- "organizations",
2916
- where2("members", "array-contains", email),
2917
- where2("masterSubscriptionStatus", "==", "active"),
2918
- limit2(1)
2919
- );
2920
- if (!organizationSnapshot.empty) {
2921
- const orgData = organizationSnapshot.data[0];
2922
- return {
2923
- hasUnlimitedAccess: true,
2924
- subscriptionId: orgData == null ? void 0 : orgData.masterSubscriptionId,
2925
- organizationId: orgData.id,
2926
- organizationName: orgData.name || "Unknown Organization",
2927
- subscriptionEndDate: orgData.masterSubscriptionEndDate || null,
2928
- accessType: "organization"
2929
- };
2930
- }
2931
- const institutionSnapshot = await api.getDocs(
2932
- "institution_subscriptions",
2933
- where2("users", "array-contains", email),
2934
- where2("active", "==", true),
2935
- limit2(1)
2936
- );
2937
- if (!institutionSnapshot.empty) {
2938
- const institutionData = institutionSnapshot.data[0];
2939
- const isUnlimited = (institutionData == null ? void 0 : institutionData.plan) === "organization" || (institutionData == null ? void 0 : institutionData.plan) === "school_starter";
2940
- return {
2941
- hasUnlimitedAccess: isUnlimited,
2942
- subscriptionId: institutionData.id,
2943
- organizationId: institutionData == null ? void 0 : institutionData.institutionId,
2944
- organizationName: institutionData.name || institutionData.institutionId || "Legacy Institution",
2945
- subscriptionEndDate: institutionData.endDate || null,
2946
- accessType: "institution_subscriptions"
2947
- };
2948
- }
2949
- return {
2950
- hasUnlimitedAccess: false,
2951
- subscriptionId: null,
2952
- organizationId: null,
2953
- organizationName: null,
2954
- subscriptionEndDate: null,
2955
- accessType: "individual"
2956
- };
2957
- } catch (error) {
2958
- console.error("Error checking organization access:", error);
2959
- return {
2960
- hasUnlimitedAccess: false,
2961
- subscriptionId: null,
2962
- organizationId: null,
2963
- organizationName: null,
2964
- subscriptionEndDate: null,
2965
- accessType: "individual"
2966
- };
2967
- }
2968
- };
2969
-
2970
- // src/hooks/useUpdateStudentVoc.ts
2971
- var useUpdateStudentVocab = (page) => {
2972
- const { user } = useSpeakableApi();
2973
- const currentUserId = user == null ? void 0 : user.auth.uid;
2974
- if (!page || !currentUserId || !page.target_text || !page.language) {
2975
- return {
2976
- studentVocabMarkVoiceSuccess: void 0,
2977
- studentVocabMarkVoiceFail: void 0
2978
- };
2979
- }
2980
- const getDataObject = () => {
2981
- var _a, _b;
2982
- const { serverTimestamp: serverTimestamp2 } = api.accessHelpers();
2983
- const language = (_a = page.language) != null ? _a : "en";
2984
- const word = (_b = page.target_text) != null ? _b : "";
2985
- const phrase_length = getPhraseLength(word);
2986
- const wordHash = getWordHash(word, language);
2987
- const docPath = `users/${currentUserId}/vocab/${wordHash}`;
2988
- const communityPath = `checked-pronunciations/${wordHash}`;
2989
- const id = `${language}-${cleanString(word)}`;
2990
- const data = {
2991
- id,
2992
- word,
2993
- words: (word == null ? void 0 : word.split(" ")) || [],
2994
- wordHash,
2995
- language,
2996
- lastSeen: serverTimestamp2(),
2997
- phrase_length
2998
- };
2999
- return {
3000
- docPath,
3001
- communityPath,
3002
- data
3003
- };
3004
- };
3005
- const markVoiceSuccess = async () => {
3006
- const { docPath, communityPath, data } = getDataObject();
3007
- const { increment: increment2 } = api.accessQueryConstraints();
3008
- const { serverTimestamp: serverTimestamp2 } = api.accessHelpers();
3009
- data.voiceSuccess = increment2(1);
3010
- try {
3011
- await api.updateDoc(docPath, data);
3012
- } catch (error) {
3013
- if (error instanceof Error && error.message === "not-found") {
3014
- data.firstSeen = serverTimestamp2();
3015
- await api.setDoc(docPath, data, { merge: true });
3016
- } else {
3017
- console.log(error);
3018
- }
3019
- }
3020
- try {
3021
- data.pronunciations = increment2(1);
3022
- await api.setDoc(communityPath, data, { merge: true });
3023
- } catch (error) {
3024
- console.log(error);
3025
- }
3026
- };
3027
- const markVoiceFail = async () => {
3028
- const { docPath, communityPath, data } = getDataObject();
3029
- const { increment: increment2 } = api.accessQueryConstraints();
3030
- const { serverTimestamp: serverTimestamp2 } = api.accessHelpers();
3031
- data.voiceFail = increment2(1);
3032
- try {
3033
- await api.updateDoc(docPath, data);
3034
- } catch (error) {
3035
- if (error instanceof Error && error.message === "not-found") {
3036
- data.firstSeen = serverTimestamp2();
3037
- await api.setDoc(docPath, data, { merge: true });
3038
- } else {
3039
- console.log(error);
3040
- }
3041
- }
3042
- try {
3043
- data.fails = increment2(1);
3044
- await api.setDoc(communityPath, data, { merge: true });
3045
- } catch (error) {
3046
- console.log(error);
3047
- }
3048
- };
3049
- return {
3050
- studentVocabMarkVoiceSuccess: markVoiceSuccess,
3051
- studentVocabMarkVoiceFail: markVoiceFail
3052
- };
3053
- };
3054
-
3055
- // src/hooks/useActivityFeedbackAccess.ts
3056
- var import_react_query7 = require("@tanstack/react-query");
3057
- var activityFeedbackAccessQueryKeys = {
3058
- activityFeedbackAccess: (args) => ["activityFeedbackAccess", ...Object.values(args)]
3059
- };
3060
- var useActivityFeedbackAccess = ({
3061
- aiEnabled = false,
3062
- isActivityRoute = false
3063
- }) => {
3064
- var _a, _b, _c;
3065
- const { user } = useSpeakableApi();
3066
- const uid = user.auth.uid;
3067
- const isTeacher = (_a = user.profile) == null ? void 0 : _a.isTeacher;
3068
- const isStudent = (_b = user.profile) == null ? void 0 : _b.isStudent;
3069
- const userRoles = ((_c = user.profile) == null ? void 0 : _c.roles) || [];
3070
- const query2 = (0, import_react_query7.useQuery)({
3071
- queryKey: activityFeedbackAccessQueryKeys.activityFeedbackAccess({
3072
- aiEnabled,
3073
- isActivityRoute
3074
- }),
3075
- queryFn: async () => {
3076
- var _a2, _b2, _c2;
3077
- if (!uid) {
3078
- return {
3079
- canAccessFeedback: false,
3080
- reason: "Missing user ID",
3081
- isUnlimited: false,
3082
- accessType: "none"
3083
- };
3084
- }
3085
- try {
3086
- if (aiEnabled) {
3087
- return {
3088
- canAccessFeedback: true,
3089
- reason: "AI feedback enabled",
3090
- isUnlimited: true,
3091
- accessType: "ai_enabled"
3092
- };
3093
- }
3094
- if (isTeacher || userRoles.includes("ADMIN")) {
3095
- return {
3096
- canAccessFeedback: true,
3097
- reason: "Teacher preview access",
3098
- isUnlimited: true,
3099
- accessType: "teacher_preview"
3100
- };
3101
- }
3102
- if (isStudent && isActivityRoute) {
3103
- try {
3104
- const result = await ((_c2 = (_b2 = (_a2 = api).httpsCallable) == null ? void 0 : _b2.call(_a2, "checkStudentTeacherPlan")) == null ? void 0 : _c2({
3105
- studentId: uid
3106
- }));
3107
- const planCheckResult = result.data;
3108
- if (planCheckResult.canAccessFeedback) {
3109
- return {
3110
- canAccessFeedback: true,
3111
- reason: planCheckResult.reason || "Student access via teacher with active plan",
3112
- isUnlimited: planCheckResult.hasTeacherWithUnlimitedAccess,
3113
- accessType: "student_with_teacher_plan"
3114
- };
3115
- } else {
3116
- return {
3117
- canAccessFeedback: false,
3118
- reason: planCheckResult.reason || "No teacher with active plan found",
3119
- isUnlimited: false,
3120
- accessType: "none"
3121
- };
3122
- }
3123
- } catch (error) {
3124
- console.error("Error checking student teacher plan:", error);
3125
- return {
3126
- canAccessFeedback: false,
3127
- reason: "Error checking teacher plans",
3128
- isUnlimited: false,
3129
- accessType: "none"
3130
- };
3131
- }
3132
- }
3133
- return {
3134
- canAccessFeedback: false,
3135
- reason: "No access permissions found for current context",
3136
- isUnlimited: false,
3137
- accessType: "none"
3138
- };
3139
- } catch (error) {
3140
- console.error("Error checking activity feedback access:", error);
3141
- return {
3142
- canAccessFeedback: false,
3143
- reason: "Error checking access permissions",
3144
- isUnlimited: false,
3145
- accessType: "none"
3146
- };
3147
- }
3148
- },
3149
- enabled: !!uid,
3150
- staleTime: 5 * 60 * 1e3,
3151
- // 5 minutes
3152
- gcTime: 10 * 60 * 1e3
3153
- // 10 minutes
3154
- });
3155
- return {
3156
- ...query2
3157
- };
3158
- };
3159
-
3160
- // src/hooks/useOpenAI.ts
3161
- var useBaseOpenAI = ({
3162
- onTranscriptSuccess,
3163
- onTranscriptError,
3164
- onCompletionSuccess,
3165
- onCompletionError,
3166
- aiEnabled,
3167
- submitAudioResponse,
3168
- uploadAudioAndGetTranscript,
3169
- onGetAudioUrlAndTranscript
3170
- }) => {
3171
- const { user, queryClient } = useSpeakableApi();
3172
- const currentUserId = user.auth.uid;
3173
- const { data: feedbackAccess } = useActivityFeedbackAccess({
3174
- aiEnabled
3175
- });
3176
- const getTranscript = async (audioUrl, language, prompt) => {
3177
- var _a, _b, _c, _d;
3178
- const getGeminiTranscript = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "getGeminiTranscript");
3179
- const getAssemblyAITranscript = (_d = (_c = api).httpsCallable) == null ? void 0 : _d.call(_c, "transcribeAssemblyAIAudio");
3180
- try {
3181
- const { data } = await (getGeminiTranscript == null ? void 0 : getGeminiTranscript({
3182
- audioUrl,
3183
- targetLanguage: language,
3184
- prompt: prompt || ""
3185
- }));
3186
- const transcript = data.transcript;
3187
- if (transcript) {
3188
- return transcript;
3189
- }
3190
- } catch (error) {
3191
- console.log("Gemini transcript failed, trying AssemblyAI fallback:", error);
3192
- }
3193
- try {
3194
- const response = await (getAssemblyAITranscript == null ? void 0 : getAssemblyAITranscript({
3195
- audioUrl,
3196
- language
3197
- }));
3198
- const transcript = response == null ? void 0 : response.data;
3199
- if (transcript) {
3200
- return transcript;
3201
- }
3202
- throw new Error("Both transcript services failed");
3203
- } catch (error) {
3204
- console.log("AssemblyAI transcript also failed:", error);
3205
- onTranscriptError({
3206
- type: "TRANSCRIPT",
3207
- message: (error == null ? void 0 : error.message) || "Error getting transcript from both services"
3208
- });
3209
- throw new Error(error);
3210
- }
3211
- };
3212
- const getFreeResponseCompletion = async (messages, isFreeResponse, feedbackLanguage, gradingStandard = "actfl") => {
3213
- var _a, _b, _c, _d, _e;
3214
- const responseTool = getRespondCardTool({
3215
- language: feedbackLanguage,
3216
- standard: gradingStandard
3217
- });
3218
- try {
3219
- const createChatCompletion = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "createChatCompletion");
3220
- const {
3221
- data: {
3222
- response,
3223
- prompt_tokens = 0,
3224
- completion_tokens = 0,
3225
- success: aiSuccess = false
3226
- // the AI was able to generate a response
3227
- }
3228
- } = await (createChatCompletion == null ? void 0 : createChatCompletion({
3229
- chat: {
3230
- model: isFreeResponse ? "gpt-4-1106-preview" : "gpt-3.5-turbo-1106",
3231
- messages,
3232
- temperature: 0.7,
3233
- ...responseTool
3234
- },
3235
- type: isFreeResponse ? "LONG_RESPONSE" : "SHORT_RESPONSE"
3236
- }));
3237
- 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) || "{}");
3238
- const result = {
3239
- ...functionArguments,
3240
- prompt_tokens,
3241
- completion_tokens,
3242
- aiSuccess
3243
- };
3244
- onCompletionSuccess(result);
3245
- return result;
3246
- } catch (error) {
3247
- onCompletionError({
3248
- type: "COMPLETION",
3249
- message: (error == null ? void 0 : error.message) || "Error getting completion"
3250
- });
3251
- throw new Error(error);
3252
- }
3253
- };
3254
- const getFeedback = async ({
3255
- cardId,
3256
- language = "en",
3257
- // required
3258
- writtenResponse = null,
3259
- // if the type = RESPOND_WRITE
3260
- audio = null,
3261
- autoGrade = true,
3262
- file = null,
3263
- pagePrompt = null
3264
- }) => {
3265
- try {
3266
- if (!(feedbackAccess == null ? void 0 : feedbackAccess.canAccessFeedback)) {
3267
- const result = {
3268
- noFeedbackAvailable: true,
3269
- success: true,
3270
- reason: (feedbackAccess == null ? void 0 : feedbackAccess.reason) || "No feedback access",
3271
- accessType: (feedbackAccess == null ? void 0 : feedbackAccess.accessType) || "none"
3272
- };
3273
- onCompletionSuccess(result);
3274
- return result;
3275
- }
3276
- let transcript;
3277
- let audioUrl = void 0;
3278
- if (writtenResponse) {
3279
- transcript = writtenResponse;
3280
- onTranscriptSuccess(writtenResponse);
3281
- } else if (typeof audio === "string" && file) {
3282
- if (feedbackAccess == null ? void 0 : feedbackAccess.canAccessFeedback) {
3283
- transcript = await getTranscript(audio, language, pagePrompt != null ? pagePrompt : "");
3284
- audioUrl = audio;
3285
- onTranscriptSuccess(transcript);
3286
- } else {
3287
- console.info(
3288
- `Transcript not available: ${(feedbackAccess == null ? void 0 : feedbackAccess.reason) || "No feedback access"}`
3289
- );
3290
- }
3291
- } else {
3292
- const response = await uploadAudioAndGetTranscript(audio || "", language, pagePrompt != null ? pagePrompt : "");
3293
- transcript = response.transcript;
3294
- audioUrl = response.audioUrl;
3295
- }
3296
- onGetAudioUrlAndTranscript == null ? void 0 : onGetAudioUrlAndTranscript({ transcript, audioUrl });
3297
- if (feedbackAccess == null ? void 0 : feedbackAccess.canAccessFeedback) {
3298
- const results = await getAIResponse({
3299
- cardId,
3300
- transcript: transcript || ""
3301
- });
3302
- let output = results;
3303
- if (!autoGrade) {
3304
- output = {
3305
- ...output,
3306
- noFeedbackAvailable: true,
3307
- success: true
3308
- };
3309
- }
3310
- onCompletionSuccess(output);
3311
- return output;
3312
- } else {
3313
- const result = {
3314
- noFeedbackAvailable: true,
3315
- success: true,
3316
- reason: (feedbackAccess == null ? void 0 : feedbackAccess.reason) || "No feedback access",
3317
- accessType: (feedbackAccess == null ? void 0 : feedbackAccess.accessType) || "none"
3318
- };
3319
- onCompletionSuccess(result);
3320
- return result;
3321
- }
3322
- } catch (error) {
3323
- console.error("Error getting feedback:", error);
3324
- throw new Error(error);
3325
- }
3326
- };
3327
- const getAIResponse = async ({ cardId, transcript }) => {
3328
- var _a, _b, _c, _d, _e;
3329
- try {
3330
- const getGeminiFeedback = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "callGetFeedback");
3331
- const getProficiencyEstimate = (_d = (_c = api).httpsCallable) == null ? void 0 : _d.call(_c, "getProficiencyEstimate");
3332
- const card = getCardFromCache({
3333
- cardId,
3334
- queryClient
3335
- });
3336
- let feedbackData;
3337
- let proficiencyData = {};
3338
- if (card && card.grading_method === "manual") {
3339
- } else if (card && card.grading_method !== "standards_based") {
3340
- const [geminiResult, proficiencyResult] = await Promise.all([
3341
- getGeminiFeedback == null ? void 0 : getGeminiFeedback({
3342
- cardId,
3343
- studentId: currentUserId,
3344
- studentResponse: transcript
3345
- }),
3346
- getProficiencyEstimate == null ? void 0 : getProficiencyEstimate({
3347
- cardId,
3348
- studentId: currentUserId,
3349
- studentResponse: transcript
3350
- })
3351
- ]);
3352
- proficiencyData = (proficiencyResult == null ? void 0 : proficiencyResult.data) || {};
3353
- feedbackData = {
3354
- ...(_e = geminiResult == null ? void 0 : geminiResult.data) != null ? _e : {},
3355
- // @ts-ignore
3356
- proficiency_level: (proficiencyData == null ? void 0 : proficiencyData.proficiency_level) || null
3357
- };
3358
- } else {
3359
- const geminiResult = await (getGeminiFeedback == null ? void 0 : getGeminiFeedback({
3360
- cardId,
3361
- studentId: currentUserId,
3362
- studentResponse: transcript
3363
- }));
3364
- feedbackData = geminiResult == null ? void 0 : geminiResult.data;
3365
- }
3366
- const results = {
3367
- ...proficiencyData,
3368
- ...feedbackData,
3369
- aiSuccess: true,
3370
- promptSuccess: (feedbackData == null ? void 0 : feedbackData.success) || false,
3371
- transcript
3372
- };
3373
- return results;
3374
- } catch (error) {
3375
- onCompletionError({
3376
- type: "AI_FEEDBACK",
3377
- message: (error == null ? void 0 : error.message) || "Error getting ai feedback"
3378
- });
3379
- throw new Error(error);
3380
- }
3381
- };
3382
- return {
3383
- submitAudioResponse,
3384
- uploadAudioAndGetTranscript,
3385
- getTranscript,
3386
- getFreeResponseCompletion,
3387
- getFeedback
3388
- };
3389
- };
3390
-
3391
- // src/lib/create-firebase-client-native.ts
3392
- var import_firestore = require("@react-native-firebase/firestore");
3393
-
3394
1045
  // src/lib/create-firebase-client.ts
3395
1046
  function createFsClientBase({
3396
1047
  db,