@speakableio/core 0.1.20 → 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,5 +1,37 @@
1
1
  // src/providers/SpeakableProvider.tsx
2
2
  import { createContext, useContext, useEffect, useState } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ var FsCtx = createContext(null);
5
+ function SpeakableProvider({
6
+ user,
7
+ children,
8
+ queryClient,
9
+ permissions,
10
+ fsClient
11
+ }) {
12
+ const [speakableApi, setSpeakableApi] = useState(null);
13
+ useEffect(() => {
14
+ setSpeakableApi(fsClient);
15
+ }, [fsClient]);
16
+ if (!speakableApi) return null;
17
+ return /* @__PURE__ */ jsx(
18
+ FsCtx.Provider,
19
+ {
20
+ value: {
21
+ speakableApi,
22
+ queryClient,
23
+ user,
24
+ permissions
25
+ },
26
+ children
27
+ }
28
+ );
29
+ }
30
+ function useSpeakableApi() {
31
+ const ctx = useContext(FsCtx);
32
+ if (!ctx) throw new Error("useSpeakableApi must be used within a SpeakableProvider");
33
+ return ctx;
34
+ }
3
35
 
4
36
  // src/utils/error-handler.ts
5
37
  var ServiceError = class extends Error {
@@ -55,7 +87,12 @@ var FirebaseAPI = class _FirebaseAPI {
55
87
  return this.config.helpers;
56
88
  }
57
89
  httpsCallable(functionName) {
58
- return this.config?.httpsCallable(functionName);
90
+ var _a;
91
+ return (_a = this.config) == null ? void 0 : _a.httpsCallable(functionName);
92
+ }
93
+ logEvent(name, data) {
94
+ var _a;
95
+ (_a = this.config) == null ? void 0 : _a.logEvent(name, data);
59
96
  }
60
97
  accessQueryConstraints() {
61
98
  const { query, orderBy, limit, startAt, startAfter, endAt, endBefore } = this.helpers;
@@ -87,8 +124,6 @@ var FirebaseAPI = class _FirebaseAPI {
87
124
  id: docSnap.id,
88
125
  ...docSnap.data()
89
126
  } : null;
90
- console.log("getDoc", path);
91
- console.log("getDoc db", this.db);
92
127
  return {
93
128
  id: docSnap.id,
94
129
  data
@@ -99,8 +134,6 @@ var FirebaseAPI = class _FirebaseAPI {
99
134
  const collectionRef = collection(this.db, path);
100
135
  const q = queryConstraints.length > 0 ? query(collectionRef, ...queryConstraints) : collectionRef;
101
136
  const querySnapshot = await getDocs(q);
102
- console.log("getDocs", path, queryConstraints);
103
- console.log("getDocs db", this.db);
104
137
  const data = querySnapshot.docs.map((doc) => ({
105
138
  id: doc.id,
106
139
  data: doc.data()
@@ -122,22 +155,16 @@ var FirebaseAPI = class _FirebaseAPI {
122
155
  async setDoc(path, data, options = {}) {
123
156
  const { setDoc, doc } = this.helpers;
124
157
  const docRef = doc(this.db, path);
125
- console.log("setDoc", path, data);
126
- console.log("setDoc db", this.db);
127
158
  await setDoc(docRef, data, options);
128
159
  }
129
160
  async updateDoc(path, data) {
130
161
  const { updateDoc, doc } = this.helpers;
131
- console.log("updateDoc", path, data);
132
- console.log("updateDoc db", this.db);
133
162
  const docRef = doc(this.db, path);
134
163
  await updateDoc(docRef, data);
135
164
  }
136
165
  async deleteDoc(path) {
137
166
  const { deleteDoc, doc } = this.helpers;
138
167
  const docRef = doc(this.db, path);
139
- console.log("deleteDoc", path);
140
- console.log("deleteDoc db", this.db);
141
168
  await deleteDoc(docRef);
142
169
  }
143
170
  async runTransaction(updateFunction) {
@@ -240,12 +267,13 @@ var _attachScoresAssignment = async ({
240
267
  return acc;
241
268
  }, {});
242
269
  const assignmentsWithScores = assignments.map((a) => {
270
+ var _a;
243
271
  return {
244
272
  ...a,
245
273
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/ban-ts-comment
246
274
  // @ts-ignore
247
275
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
248
- scores: scoresObject[a.id] ?? null
276
+ scores: (_a = scoresObject[a.id]) != null ? _a : null
249
277
  };
250
278
  });
251
279
  return assignmentsWithScores;
@@ -274,6 +302,7 @@ var checkAssignmentAvailability = (scheduledTime) => {
274
302
 
275
303
  // src/domains/assignment/services/get-assignment.service.ts
276
304
  async function _getAssignment(params) {
305
+ var _a;
277
306
  const path = refsAssignmentFiresotre.assignment({ id: params.assignmentId });
278
307
  const response = await api.getDoc(path);
279
308
  if (!response.data) return null;
@@ -283,7 +312,7 @@ async function _getAssignment(params) {
283
312
  ...assignment,
284
313
  isAvailable,
285
314
  id: params.assignmentId,
286
- scheduledTime: assignment.scheduledTime ?? null
315
+ scheduledTime: (_a = assignment.scheduledTime) != null ? _a : null
287
316
  };
288
317
  if (params.analyticType) {
289
318
  const assignmentsWithScores = await attachScoresAssignment({
@@ -505,7 +534,7 @@ var purify = (word) => {
505
534
  return word.normalize("NFD").replace(/\/([^" "]*)/g, "").replace(/\([^()]*\)/g, "").replace(/([^()]*)/g, "").replace(/[\u0300-\u036f]/g, "").replace(/[-]/g, " ").replace(/[.,/#!¡¿?؟。,.?$%^&*;:{}=\-_`~()’'…\s]/g, "").replace(/\s\s+/g, " ").toLowerCase().trim();
506
535
  };
507
536
  var cleanString = (words) => {
508
- const splitWords = words?.split("+");
537
+ const splitWords = words == null ? void 0 : words.split("+");
509
538
  if (splitWords && splitWords.length === 1) {
510
539
  const newWord = purify(words);
511
540
  return newWord;
@@ -519,13 +548,14 @@ var cleanString = (words) => {
519
548
  var getWordHash = (word, language) => {
520
549
  const cleanedWord = cleanString(word);
521
550
  const wordHash = sha1(`${language}-${cleanedWord}`);
551
+ console.log("wordHash core library", wordHash);
522
552
  return wordHash;
523
553
  };
524
554
 
525
555
  // src/domains/cards/services/get-card-verification-status.service.ts
526
556
  var charactarLanguages = ["zh", "ja", "ko"];
527
557
  var getVerificationStatus = async (target_text, language) => {
528
- if (target_text?.length < 3 && !charactarLanguages.includes(language)) {
558
+ if ((target_text == null ? void 0 : target_text.length) < 3 && !charactarLanguages.includes(language)) {
529
559
  return "NOT_RECOMMENDED" /* NOT_RECOMMENDED */;
530
560
  }
531
561
  const hash = getWordHash(target_text, language);
@@ -758,16 +788,18 @@ var SpeakableFirebaseFunctions = {
758
788
  submitAssignmentV2: api.httpsCallable("submitLTIAssignmentScoreV2"),
759
789
  submitAssessment: api.httpsCallable("submitAssessment"),
760
790
  sendAssessmentScoredEmail: api.httpsCallable("sendAssessmentScoredEmail"),
761
- createNotification: api.httpsCallable("createNotificationV2")
791
+ createNotification: api.httpsCallable("createNotificationV2"),
792
+ updateCourseAnalytics: api.httpsCallable("handleCouresAnalyticsEvent")
762
793
  };
763
794
 
764
795
  // src/domains/notification/services/send-notification.service.ts
765
796
  var _sendNotification = async (sendTo, notification) => {
766
- const results = await SpeakableFirebaseFunctions.createNotification?.({
797
+ var _a, _b;
798
+ const results = await ((_b = (_a = SpeakableFirebaseFunctions).createNotification) == null ? void 0 : _b.call(_a, {
767
799
  sendTo,
768
800
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
769
801
  notification
770
- });
802
+ }));
771
803
  return results;
772
804
  };
773
805
  var sendNotification = withErrorHandler(_sendNotification, "sendNotification");
@@ -833,6 +865,7 @@ var createNewAssignmentNotification = async ({
833
865
  data,
834
866
  profile
835
867
  }) => {
868
+ var _a;
836
869
  const { assignment, sendTo } = data;
837
870
  const teacherName = profile.displayName || "Your teacher";
838
871
  const dueDate = assignment.dueDateTimestamp ? dayjs2(assignment.dueDateTimestamp.toDate()).format("MMM Do") : null;
@@ -843,7 +876,7 @@ var createNewAssignmentNotification = async ({
843
876
  link: `${WEB_BASE_URL}/assignment/${assignment.id}`,
844
877
  messagePreview: `A new assignment "${assignment.name}" is now available. ${dueDate ? `Due ${dueDate}` : ""}`,
845
878
  title: "New Assignment Available!",
846
- imageUrl: profile.image?.url
879
+ imageUrl: (_a = profile.image) == null ? void 0 : _a.url
847
880
  });
848
881
  return results;
849
882
  };
@@ -852,6 +885,7 @@ var createAssessmentSubmissionNotification = async ({
852
885
  profile,
853
886
  userId
854
887
  }) => {
888
+ var _a;
855
889
  const studentName = profile.displayName || "Your student";
856
890
  const results = await sendNotification(assignment.owners, {
857
891
  courseId: assignment.courseId,
@@ -860,7 +894,7 @@ var createAssessmentSubmissionNotification = async ({
860
894
  title: `Assessment Submitted!`,
861
895
  senderName: studentName,
862
896
  messagePreview: `${studentName} has submitted the assessment "${assignment.name}"`,
863
- imageUrl: profile.image?.url
897
+ imageUrl: (_a = profile.image) == null ? void 0 : _a.url
864
898
  });
865
899
  return results;
866
900
  };
@@ -868,6 +902,7 @@ var createAssessmentScoredNotification = async ({
868
902
  data,
869
903
  profile
870
904
  }) => {
905
+ var _a, _b, _c, _d;
871
906
  const { assignment, sendTo } = data;
872
907
  const teacherName = profile.displayName || "Your teacher";
873
908
  const title = `${assignment.isAssessment ? "Assessment" : "Assignment"} Reviewed!`;
@@ -878,16 +913,16 @@ var createAssessmentScoredNotification = async ({
878
913
  link: `${WEB_BASE_URL}/assignment/${assignment.id}`,
879
914
  title,
880
915
  messagePreview,
881
- imageUrl: profile.image?.url,
916
+ imageUrl: (_a = profile.image) == null ? void 0 : _a.url,
882
917
  senderName: teacherName
883
918
  });
884
- await SpeakableFirebaseFunctions.sendAssessmentScoredEmail?.({
919
+ await ((_d = (_c = SpeakableFirebaseFunctions).sendAssessmentScoredEmail) == null ? void 0 : _d.call(_c, {
885
920
  assessmentTitle: assignment.name,
886
921
  link: `${WEB_BASE_URL}/assignment/${assignment.id}`,
887
- senderImage: profile.image?.url || "",
922
+ senderImage: ((_b = profile.image) == null ? void 0 : _b.url) || "",
888
923
  studentId: sendTo[0],
889
924
  teacherName: profile.displayName
890
- });
925
+ }));
891
926
  return results;
892
927
  };
893
928
 
@@ -899,14 +934,15 @@ var notificationQueryKeys = {
899
934
  var useCreateNotification = () => {
900
935
  const { user, queryClient } = useSpeakableApi();
901
936
  const handleCreateNotifications = async (type, data) => {
937
+ var _a, _b;
902
938
  const result = await createNotification({
903
939
  type,
904
940
  userId: user.auth.uid,
905
- profile: user?.profile ?? {},
941
+ profile: (_a = user == null ? void 0 : user.profile) != null ? _a : {},
906
942
  data
907
943
  });
908
944
  queryClient.invalidateQueries({
909
- queryKey: notificationQueryKeys.byId(user?.auth.uid ?? "")
945
+ queryKey: notificationQueryKeys.byId((_b = user == null ? void 0 : user.auth.uid) != null ? _b : "")
910
946
  });
911
947
  return result;
912
948
  };
@@ -916,17 +952,18 @@ var useCreateNotification = () => {
916
952
  };
917
953
 
918
954
  // src/lib/create-firebase-client.ts
919
- async function createFsClient({
955
+ function createFsClientBase({
920
956
  db,
921
- platform,
922
- httpsCallable
957
+ helpers,
958
+ httpsCallable,
959
+ logEvent
923
960
  }) {
924
961
  const dbAsFirestore = db;
925
- const helpers = platform === "web" ? await import("firebase/firestore") : await import("@react-native-firebase/firestore");
926
962
  api.initialize({
927
963
  db: dbAsFirestore,
928
964
  helpers,
929
- httpsCallable
965
+ httpsCallable,
966
+ logEvent
930
967
  });
931
968
  return {
932
969
  assignmentRepo: createAssignmentRepo(),
@@ -934,48 +971,6 @@ async function createFsClient({
934
971
  };
935
972
  }
936
973
 
937
- // src/providers/SpeakableProvider.tsx
938
- import { jsx } from "react/jsx-runtime";
939
- var FsCtx = createContext(null);
940
- function SpeakableProvider({
941
- db,
942
- platform,
943
- children,
944
- queryClient,
945
- user,
946
- permissions,
947
- httpsCallable
948
- }) {
949
- const [speakableApi, setSpeakableApi] = useState(null);
950
- useEffect(() => {
951
- createFsClient({
952
- db,
953
- httpsCallable,
954
- platform
955
- }).then((repos) => {
956
- setSpeakableApi(repos);
957
- });
958
- }, [db, platform, httpsCallable]);
959
- if (!speakableApi) return null;
960
- return /* @__PURE__ */ jsx(
961
- FsCtx.Provider,
962
- {
963
- value: {
964
- speakableApi,
965
- queryClient,
966
- user,
967
- permissions
968
- },
969
- children
970
- }
971
- );
972
- }
973
- function useSpeakableApi() {
974
- const ctx = useContext(FsCtx);
975
- if (!ctx) throw new Error("useSpeakableApi must be used within a SpeakableProvider");
976
- return ctx;
977
- }
978
-
979
974
  // src/domains/assignment/hooks/score-hooks.ts
980
975
  import { useMutation as useMutation2, useQuery as useQuery3 } from "@tanstack/react-query";
981
976
 
@@ -1174,7 +1169,10 @@ var SpeakablePlanHierarchy = [
1174
1169
  // src/hooks/usePermissions.ts
1175
1170
  var usePermissions = () => {
1176
1171
  const { permissions } = useSpeakableApi();
1177
- const has = (permission) => permissions.permissions?.includes(permission);
1172
+ const has = (permission) => {
1173
+ var _a;
1174
+ return (_a = permissions.permissions) == null ? void 0 : _a.includes(permission);
1175
+ };
1178
1176
  return {
1179
1177
  plan: permissions.plan,
1180
1178
  permissionsLoaded: permissions.loaded,
@@ -1204,6 +1202,7 @@ var useGoogleClassroom = () => {
1204
1202
  googleUserId = null
1205
1203
  // optional to override the user's googleUserId
1206
1204
  }) => {
1205
+ var _a, _b;
1207
1206
  try {
1208
1207
  const { googleClassroomUserId = null } = scores;
1209
1208
  const googleId = googleUserId || googleClassroomUserId;
@@ -1213,14 +1212,14 @@ var useGoogleClassroom = () => {
1213
1212
  message: "No Google Classroom ID found"
1214
1213
  };
1215
1214
  const { courseWorkId, maxPoints, owners, courseId } = assignment;
1216
- const draftGrade = scores?.score ? scores?.score / 100 * maxPoints : 0;
1217
- const result = await SpeakableFirebaseFunctions.submitAssignmentToGoogleClassroomV2?.({
1215
+ const draftGrade = (scores == null ? void 0 : scores.score) ? (scores == null ? void 0 : scores.score) / 100 * maxPoints : 0;
1216
+ const result = await ((_b = (_a = SpeakableFirebaseFunctions).submitAssignmentToGoogleClassroomV2) == null ? void 0 : _b.call(_a, {
1218
1217
  teacherId: owners[0],
1219
1218
  courseId,
1220
1219
  courseWorkId,
1221
1220
  userId: googleId,
1222
1221
  draftGrade
1223
- });
1222
+ }));
1224
1223
  return result;
1225
1224
  } catch (error) {
1226
1225
  return { error: true, message: error.message };
@@ -1231,6 +1230,64 @@ var useGoogleClassroom = () => {
1231
1230
  };
1232
1231
  };
1233
1232
 
1233
+ // src/lib/firebase/firebase-analytics/grading-standard.ts
1234
+ var logGradingStandardLog = (data) => {
1235
+ var _a, _b;
1236
+ if (data.courseId && data.type && data.level) {
1237
+ (_b = (_a = SpeakableFirebaseFunctions).updateCourseAnalytics) == null ? void 0 : _b.call(_a, {
1238
+ eventType: data.type || "custom",
1239
+ level: data.level,
1240
+ courseId: data.courseId
1241
+ });
1242
+ }
1243
+ api.logEvent("logGradingStandard", data);
1244
+ };
1245
+
1246
+ // src/constants/analytics.constants.ts
1247
+ var ANALYTICS_EVENT_TYPES = {
1248
+ VOICE_SUCCESS: "voice_success",
1249
+ VOICE_FAIL: "voice_fail",
1250
+ RESPOND_CARD_SUCCESS: "respond_card_success",
1251
+ RESPOND_CARD_FAIL: "respond_card_fail",
1252
+ RESPOND_WRITE_CARD_SUCCESS: "respond_write_card_success",
1253
+ RESPOND_WRITE_CARD_FAIL: "respond_write_card_fail",
1254
+ RESPOND_FREE_PLAN: "respond_free_plan",
1255
+ RESPOND_WRITE_FREE_PLAN: "respond_write_free_plan",
1256
+ SUBMISSION: "assignment_submitted",
1257
+ ASSIGNMENT_STARTED: "assignment_started",
1258
+ CREATE_ASSIGNMENT: "create_assignment",
1259
+ MC_SUCCESS: "multiple_choice_success",
1260
+ MC_FAIL: "multiple_choice_fail",
1261
+ ACTFL_LEVEL: "actfl_level",
1262
+ WIDA_LEVEL: "wida_level"
1263
+ };
1264
+
1265
+ // src/lib/firebase/firebase-analytics/assignment.ts
1266
+ var logOpenAssignment = (data = {}) => {
1267
+ api.logEvent("open_assignment", data);
1268
+ };
1269
+ var logOpenActivityPreview = (data = {}) => {
1270
+ api.logEvent("open_activity_preview", data);
1271
+ };
1272
+ var logSubmitAssignment = (data = {}) => {
1273
+ var _a, _b;
1274
+ (_b = (_a = SpeakableFirebaseFunctions).updateCourseAnalytics) == null ? void 0 : _b.call(_a, {
1275
+ eventType: ANALYTICS_EVENT_TYPES.SUBMISSION,
1276
+ ...data
1277
+ });
1278
+ api.logEvent(ANALYTICS_EVENT_TYPES.SUBMISSION, data);
1279
+ };
1280
+ var logStartAssignment = (data = {}) => {
1281
+ var _a, _b;
1282
+ if (data.courseId) {
1283
+ (_b = (_a = SpeakableFirebaseFunctions).updateCourseAnalytics) == null ? void 0 : _b.call(_a, {
1284
+ eventType: ANALYTICS_EVENT_TYPES.ASSIGNMENT_STARTED,
1285
+ ...data
1286
+ });
1287
+ }
1288
+ api.logEvent(ANALYTICS_EVENT_TYPES.ASSIGNMENT_STARTED, data);
1289
+ };
1290
+
1234
1291
  // src/domains/assignment/utils/create-default-score.ts
1235
1292
  var defaultScore = (props) => {
1236
1293
  const { serverTimestamp } = api.accessHelpers();
@@ -1264,17 +1321,18 @@ var refsScoresPractice = {
1264
1321
 
1265
1322
  // src/domains/assignment/services/create-score.service.ts
1266
1323
  async function _createScore(params) {
1324
+ var _a, _b;
1267
1325
  if (params.isAssignment) {
1268
1326
  const ref = refsAssignmentFiresotre.assignmentScores({
1269
1327
  id: params.activityId,
1270
1328
  userId: params.userId
1271
1329
  });
1272
- await SpeakableFirebaseFunctions.updateAssignmentGradebookStatus?.({
1330
+ await ((_b = (_a = SpeakableFirebaseFunctions).updateAssignmentGradebookStatus) == null ? void 0 : _b.call(_a, {
1273
1331
  assignmentId: params.activityId,
1274
1332
  userId: params.userId,
1275
1333
  status: "IN_PROGRESS",
1276
1334
  score: null
1277
- });
1335
+ }));
1278
1336
  await api.setDoc(ref, params.scoreData, { merge: true });
1279
1337
  return {
1280
1338
  id: params.userId
@@ -1313,6 +1371,9 @@ async function getAssignmentScore({
1313
1371
  }),
1314
1372
  assignmentId: assignment.id
1315
1373
  };
1374
+ logStartAssignment({
1375
+ courseId: assignment.courseId
1376
+ });
1316
1377
  const result = await createScore({
1317
1378
  activityId: assignment.id,
1318
1379
  userId,
@@ -1371,17 +1432,17 @@ var getScore = withErrorHandler(_getScore, "getScore");
1371
1432
 
1372
1433
  // src/domains/assignment/utils/calculateScoreAndProgress.ts
1373
1434
  var calculateScoreAndProgress = (scores, cardsList, weights) => {
1374
- console.log("calculateScoreAndProgress", scores, cardsList, weights);
1375
1435
  const totalSetPoints = cardsList.reduce((acc, cardId) => {
1376
- acc += weights?.[cardId] || 1;
1436
+ acc += (weights == null ? void 0 : weights[cardId]) || 1;
1377
1437
  return acc;
1378
1438
  }, 0);
1379
- const totalPointsAwarded = Object.keys(scores?.cards || {}).reduce((acc, cardId) => {
1380
- const cardScores = scores?.cards?.[cardId];
1381
- if (cardScores?.completed || cardScores?.score || cardScores?.score === 0) {
1382
- const score2 = cardScores?.score || cardScores?.score === 0 ? Number(cardScores?.score ?? 0) : null;
1383
- const weight = weights?.[cardId] || 1;
1384
- const fraction = (score2 ?? 0) / 100;
1439
+ const totalPointsAwarded = Object.keys((scores == null ? void 0 : scores.cards) || {}).reduce((acc, cardId) => {
1440
+ var _a, _b;
1441
+ const cardScores = (_a = scores == null ? void 0 : scores.cards) == null ? void 0 : _a[cardId];
1442
+ if ((cardScores == null ? void 0 : cardScores.completed) || (cardScores == null ? void 0 : cardScores.score) || (cardScores == null ? void 0 : cardScores.score) === 0) {
1443
+ const score2 = (cardScores == null ? void 0 : cardScores.score) || (cardScores == null ? void 0 : cardScores.score) === 0 ? Number((_b = cardScores == null ? void 0 : cardScores.score) != null ? _b : 0) : null;
1444
+ const weight = (weights == null ? void 0 : weights[cardId]) || 1;
1445
+ const fraction = (score2 != null ? score2 : 0) / 100;
1385
1446
  if (score2 || score2 === 0) {
1386
1447
  acc += weight * fraction;
1387
1448
  } else {
@@ -1390,9 +1451,10 @@ var calculateScoreAndProgress = (scores, cardsList, weights) => {
1390
1451
  }
1391
1452
  return acc;
1392
1453
  }, 0);
1393
- const totalCompletedCards = Object.keys(scores?.cards || {}).reduce((acc, cardId) => {
1394
- const cardScores = scores?.cards?.[cardId];
1395
- if (cardScores?.completed || cardScores?.score || cardScores?.score === 0) {
1454
+ const totalCompletedCards = Object.keys((scores == null ? void 0 : scores.cards) || {}).reduce((acc, cardId) => {
1455
+ var _a;
1456
+ const cardScores = (_a = scores == null ? void 0 : scores.cards) == null ? void 0 : _a[cardId];
1457
+ if ((cardScores == null ? void 0 : cardScores.completed) || (cardScores == null ? void 0 : cardScores.score) || (cardScores == null ? void 0 : cardScores.score) === 0) {
1396
1458
  acc += 1;
1397
1459
  }
1398
1460
  return acc;
@@ -1448,21 +1510,22 @@ var updateCardScore = withErrorHandler(_updateCardScore, "updateCardScore");
1448
1510
  // src/domains/assignment/services/clear-score.service.ts
1449
1511
  import dayjs3 from "dayjs";
1450
1512
  async function clearScore(params) {
1513
+ var _a, _b, _c, _d, _e;
1451
1514
  const update = {
1452
1515
  [`cards.${params.cardId}`]: {
1453
- attempts: params.cardScores.attempts ?? 1,
1454
- correct: params.cardScores.correct ?? 0,
1516
+ attempts: (_a = params.cardScores.attempts) != null ? _a : 1,
1517
+ correct: (_b = params.cardScores.correct) != null ? _b : 0,
1455
1518
  // save old score history
1456
1519
  history: [
1457
1520
  {
1458
1521
  ...params.cardScores,
1459
- attempts: params.cardScores.attempts ?? 1,
1460
- correct: params.cardScores.correct ?? 0,
1522
+ attempts: (_c = params.cardScores.attempts) != null ? _c : 1,
1523
+ correct: (_d = params.cardScores.correct) != null ? _d : 0,
1461
1524
  retryTime: dayjs3().format("YYYY-MM-DD HH:mm:ss"),
1462
1525
  history: null
1463
1526
  },
1464
1527
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
1465
- ...params.cardScores.history ?? []
1528
+ ...(_e = params.cardScores.history) != null ? _e : []
1466
1529
  ]
1467
1530
  }
1468
1531
  };
@@ -1519,6 +1582,7 @@ var submitAssignmentScore = withErrorHandler(
1519
1582
  "submitAssignmentScore"
1520
1583
  );
1521
1584
  async function handleAssessment(assignment, userId, cardIds, setWeights, fieldsUpdated, studentName) {
1585
+ var _a, _b;
1522
1586
  const path = refsAssignmentFiresotre.assignmentScores({ id: assignment.id, userId });
1523
1587
  const response = await api.getDoc(path);
1524
1588
  if (!response.data) {
@@ -1526,21 +1590,22 @@ async function handleAssessment(assignment, userId, cardIds, setWeights, fieldsU
1526
1590
  }
1527
1591
  const { score: scoreCalculated } = calculateScoreAndProgress_default(response.data, cardIds, setWeights);
1528
1592
  await api.updateDoc(path, { score: scoreCalculated, status: "PENDING_REVIEW" });
1529
- await SpeakableFirebaseFunctions.submitAssessment?.({
1593
+ await ((_b = (_a = SpeakableFirebaseFunctions).submitAssessment) == null ? void 0 : _b.call(_a, {
1530
1594
  assignmentId: assignment.id,
1531
1595
  assignmentTitle: assignment.name,
1532
1596
  userId,
1533
1597
  teacherId: assignment.owners[0],
1534
1598
  studentName
1535
- });
1599
+ }));
1536
1600
  fieldsUpdated.status = "PENDING_REVIEW";
1537
1601
  return { success: true, fieldsUpdated };
1538
1602
  }
1539
1603
  async function handleCourseAssignment(assignment, userId) {
1540
- await SpeakableFirebaseFunctions?.submitAssignmentV2?.({
1604
+ var _a, _b;
1605
+ await ((_b = (_a = SpeakableFirebaseFunctions) == null ? void 0 : _a.submitAssignmentV2) == null ? void 0 : _b.call(_a, {
1541
1606
  assignmentId: assignment.id,
1542
1607
  userId
1543
- });
1608
+ }));
1544
1609
  }
1545
1610
  async function submitPracticeScore({
1546
1611
  setId,
@@ -1602,7 +1667,7 @@ function useUpdateScore() {
1602
1667
  });
1603
1668
  },
1604
1669
  onError: (_, variables, context) => {
1605
- if (context?.previousData)
1670
+ if (context == null ? void 0 : context.previousData)
1606
1671
  queryClient.setQueryData(scoreQueryKeys.byId(variables.activityId), context.previousData);
1607
1672
  },
1608
1673
  onSettled: (_, err, variables) => {
@@ -1626,14 +1691,8 @@ function useUpdateCardScore({
1626
1691
  const mutation = useMutation2({
1627
1692
  mutationFn: async ({ cardId, cardScore }) => {
1628
1693
  const previousScores = queryClient.getQueryData(queryKey);
1629
- console.log("useUpdateCardScore", {
1630
- previousScores: previousScores ?? {},
1631
- cardId,
1632
- cardScore,
1633
- activityId
1634
- });
1635
1694
  const { progress, score, newScoreUpdated, updatedCardScore } = getScoreUpdated({
1636
- previousScores: previousScores ?? {},
1695
+ previousScores: previousScores != null ? previousScores : {},
1637
1696
  cardId,
1638
1697
  set,
1639
1698
  cardScore
@@ -1684,22 +1743,23 @@ var getScoreUpdated = ({
1684
1743
  previousScores,
1685
1744
  set
1686
1745
  }) => {
1687
- const previousCard = previousScores.cards?.[cardId];
1746
+ var _a, _b, _c, _d;
1747
+ const previousCard = (_a = previousScores.cards) == null ? void 0 : _a[cardId];
1688
1748
  const newCardScore = {
1689
- ...previousCard ?? {},
1749
+ ...previousCard != null ? previousCard : {},
1690
1750
  ...cardScore
1691
1751
  };
1692
1752
  const newScores = {
1693
1753
  ...previousScores,
1694
1754
  cards: {
1695
- ...previousScores.cards ?? {},
1755
+ ...(_b = previousScores.cards) != null ? _b : {},
1696
1756
  [cardId]: newCardScore
1697
1757
  }
1698
1758
  };
1699
1759
  const { score, progress } = calculateScoreAndProgress_default(
1700
1760
  newScores,
1701
- set?.content ?? [],
1702
- set?.weights ?? {}
1761
+ (_c = set == null ? void 0 : set.content) != null ? _c : [],
1762
+ (_d = set == null ? void 0 : set.weights) != null ? _d : {}
1703
1763
  );
1704
1764
  return {
1705
1765
  newScoreUpdated: newScores,
@@ -1714,7 +1774,8 @@ var handleOptimisticScore = ({
1714
1774
  cardScore,
1715
1775
  set
1716
1776
  }) => {
1717
- let cards = { ...score?.cards ?? {} };
1777
+ var _a, _b, _c;
1778
+ let cards = { ...(_a = score == null ? void 0 : score.cards) != null ? _a : {} };
1718
1779
  cards = {
1719
1780
  ...cards,
1720
1781
  [cardId]: {
@@ -1725,11 +1786,11 @@ var handleOptimisticScore = ({
1725
1786
  const { score: scoreValue, progress } = calculateScoreAndProgress_default(
1726
1787
  // @ts-ignore
1727
1788
  {
1728
- ...score ?? {},
1789
+ ...score != null ? score : {},
1729
1790
  cards
1730
1791
  },
1731
- set?.content ?? [],
1732
- set?.weights ?? {}
1792
+ (_b = set == null ? void 0 : set.content) != null ? _b : [],
1793
+ (_c = set == null ? void 0 : set.weights) != null ? _c : {}
1733
1794
  );
1734
1795
  return { cards, score: scoreValue, progress };
1735
1796
  };
@@ -1738,8 +1799,9 @@ function useClearScore() {
1738
1799
  const mutation = useMutation2({
1739
1800
  mutationFn: clearScore,
1740
1801
  onSettled: (result) => {
1802
+ var _a;
1741
1803
  queryClient.invalidateQueries({
1742
- queryKey: scoreQueryKeys.byId(result?.activityId ?? "")
1804
+ queryKey: scoreQueryKeys.byId((_a = result == null ? void 0 : result.activityId) != null ? _a : "")
1743
1805
  });
1744
1806
  }
1745
1807
  });
@@ -1782,6 +1844,11 @@ function useSubmitAssignmentScore({
1782
1844
  if (assignment.isAssessment) {
1783
1845
  createNotification2(SpeakableNotificationTypes.ASSESSMENT_SUBMITTED, assignment);
1784
1846
  }
1847
+ if (assignment == null ? void 0 : assignment.id) {
1848
+ logSubmitAssignment({
1849
+ courseId: assignment == null ? void 0 : assignment.courseId
1850
+ });
1851
+ }
1785
1852
  onAssignmentSubmitted(assignment.id);
1786
1853
  queryClient.setQueryData(scoreQueryKeys.byId(assignment.id), {
1787
1854
  ...scores,
@@ -1842,6 +1909,13 @@ function useSubmitPracticeScore() {
1842
1909
  // src/hooks/useActivity.ts
1843
1910
  import { useEffect as useEffect2 } from "react";
1844
1911
 
1912
+ // src/services/add-grading-standard.ts
1913
+ var addGradingStandardLog = async (gradingStandard, userId) => {
1914
+ logGradingStandardLog(gradingStandard);
1915
+ const path = `users/${userId}/grading_standard_logs`;
1916
+ await api.addDoc(path, gradingStandard);
1917
+ };
1918
+
1845
1919
  // src/hooks/useActivityTracker.ts
1846
1920
  import { v4 as v42 } from "uuid";
1847
1921
  function useActivityTracker({ userId }) {
@@ -1873,8 +1947,10 @@ function useActivityTracker({ userId }) {
1873
1947
  function useActivity({
1874
1948
  id,
1875
1949
  isAssignment,
1876
- onAssignmentSubmitted
1950
+ onAssignmentSubmitted,
1951
+ ltiData
1877
1952
  }) {
1953
+ var _a, _b, _c, _d;
1878
1954
  const { queryClient, user } = useSpeakableApi();
1879
1955
  const userId = user.auth.uid;
1880
1956
  const assignmentQuery = useAssignment({
@@ -1883,12 +1959,12 @@ function useActivity({
1883
1959
  enabled: isAssignment
1884
1960
  });
1885
1961
  const activeAssignment = assignmentQuery.data;
1886
- const setId = isAssignment ? activeAssignment?.setId ?? "" : id;
1962
+ const setId = isAssignment ? (_a = activeAssignment == null ? void 0 : activeAssignment.setId) != null ? _a : "" : id;
1887
1963
  const querySet = useSet({ setId });
1888
1964
  const setData = querySet.data;
1889
- const activityId = isAssignment ? activeAssignment?.id ?? "" : setId;
1965
+ const activityId = isAssignment ? (_b = activeAssignment == null ? void 0 : activeAssignment.id) != null ? _b : "" : setId;
1890
1966
  const { cardsObject, cardsQueries, cards } = useCards({
1891
- cardIds: setData?.content ?? [],
1967
+ cardIds: (_c = setData == null ? void 0 : setData.content) != null ? _c : [],
1892
1968
  enabled: querySet.isSuccess,
1893
1969
  asObject: true
1894
1970
  });
@@ -1896,7 +1972,7 @@ function useActivity({
1896
1972
  isAssignment,
1897
1973
  activityId: id,
1898
1974
  userId,
1899
- courseId: activeAssignment?.courseId,
1975
+ courseId: activeAssignment == null ? void 0 : activeAssignment.courseId,
1900
1976
  googleClassroomUserId: user.profile.googleClassroomUserId,
1901
1977
  enabled: isAssignment ? assignmentQuery.isSuccess : querySet.isSuccess
1902
1978
  });
@@ -1905,7 +1981,7 @@ function useActivity({
1905
1981
  activityId,
1906
1982
  isAssignment,
1907
1983
  userId,
1908
- set: querySet.data ?? void 0
1984
+ set: (_d = querySet.data) != null ? _d : void 0
1909
1985
  });
1910
1986
  const { mutationClearScore } = useClearScore();
1911
1987
  const { submitAssignmentScore: submitAssignmentScore2 } = useSubmitAssignmentScore({
@@ -1928,12 +2004,13 @@ function useActivity({
1928
2004
  cardId,
1929
2005
  wasCompleted = true
1930
2006
  }) => {
1931
- const currentCard = cardsObject?.[cardId];
1932
- if (currentCard?.type === "MULTIPLE_CHOICE" /* MULTIPLE_CHOICE */ || currentCard?.type === "READ_REPEAT" /* READ_REPEAT */) {
2007
+ var _a2, _b2;
2008
+ const currentCard = cardsObject == null ? void 0 : cardsObject[cardId];
2009
+ if ((currentCard == null ? void 0 : currentCard.type) === "MULTIPLE_CHOICE" /* MULTIPLE_CHOICE */ || (currentCard == null ? void 0 : currentCard.type) === "READ_REPEAT" /* READ_REPEAT */) {
1933
2010
  return;
1934
2011
  }
1935
2012
  const queryKeys = scoreQueryKeys.byId(activityId);
1936
- const activeCardScores = queryClient.getQueryData(queryKeys)?.cards?.[cardId];
2013
+ const activeCardScores = (_b2 = (_a2 = queryClient.getQueryData(queryKeys)) == null ? void 0 : _a2.cards) == null ? void 0 : _b2[cardId];
1937
2014
  if (activeCardScores === void 0) return;
1938
2015
  mutationClearScore.mutate({
1939
2016
  isAssignment,
@@ -1944,24 +2021,34 @@ function useActivity({
1944
2021
  });
1945
2022
  };
1946
2023
  const onSubmitScore = async () => {
2024
+ var _a2, _b2, _c2, _d2, _e, _f, _g, _h, _i, _j, _k, _l;
1947
2025
  try {
1948
2026
  let results;
1949
2027
  if (isAssignment) {
1950
- const cardScores = scoreQuery.data?.cards || {};
2028
+ const cardScores = ((_a2 = scoreQuery.data) == null ? void 0 : _a2.cards) || {};
1951
2029
  const hasPendingReview = Object.values(cardScores).some(
1952
2030
  (cardScore) => cardScore.status === "pending_review"
1953
2031
  );
1954
2032
  results = await submitAssignmentScore2({
1955
2033
  assignment: assignmentQuery.data,
1956
2034
  userId,
1957
- cardIds: setData?.content ?? [],
2035
+ cardIds: (_b2 = setData == null ? void 0 : setData.content) != null ? _b2 : [],
1958
2036
  scores: scoreQuery.data,
1959
- setWeights: setData?.weights ?? {},
2037
+ setWeights: (_c2 = setData == null ? void 0 : setData.weights) != null ? _c2 : {},
1960
2038
  status: hasPendingReview ? "PENDING_REVIEW" : "FINALIZED"
1961
2039
  });
2040
+ if ((_d2 = assignmentQuery.data) == null ? void 0 : _d2.ltiDeeplink) {
2041
+ submitLTIScore({
2042
+ maxPoints: (_e = assignmentQuery.data) == null ? void 0 : _e.maxPoints,
2043
+ score: (_g = (_f = scoreQuery.data) == null ? void 0 : _f.score) != null ? _g : 0,
2044
+ SERVICE_KEY: (_h = ltiData == null ? void 0 : ltiData.serviceKey) != null ? _h : "",
2045
+ lineItemId: (_i = ltiData == null ? void 0 : ltiData.lineItemId) != null ? _i : "",
2046
+ lti_id: (_j = ltiData == null ? void 0 : ltiData.lti_id) != null ? _j : ""
2047
+ });
2048
+ }
1962
2049
  } else {
1963
2050
  results = await submitPracticeScore2({
1964
- setId: querySet.data?.id ?? "",
2051
+ setId: (_l = (_k = querySet.data) == null ? void 0 : _k.id) != null ? _l : "",
1965
2052
  userId,
1966
2053
  scores: scoreQuery.data
1967
2054
  });
@@ -1974,9 +2061,45 @@ function useActivity({
1974
2061
  };
1975
2062
  }
1976
2063
  };
2064
+ const logGradingStandardEntry = ({
2065
+ cardId,
2066
+ gradingStandard,
2067
+ type
2068
+ }) => {
2069
+ var _a2, _b2, _c2, _d2, _e, _f, _g, _h;
2070
+ const card = cardsObject == null ? void 0 : cardsObject[cardId];
2071
+ const scoresObject = queryClient.getQueryData(scoreQueryKeys.byId(activityId));
2072
+ const cardScore = (_a2 = scoresObject == null ? void 0 : scoresObject.cards) == null ? void 0 : _a2[cardId];
2073
+ const serverTimestamp = api.helpers.serverTimestamp;
2074
+ addGradingStandardLog(
2075
+ {
2076
+ assignmentId: (_b2 = activeAssignment == null ? void 0 : activeAssignment.id) != null ? _b2 : "",
2077
+ courseId: (_c2 = activeAssignment == null ? void 0 : activeAssignment.courseId) != null ? _c2 : "",
2078
+ teacherId: (_d2 = activeAssignment == null ? void 0 : activeAssignment.owners[0]) != null ? _d2 : "",
2079
+ setId: (_e = setData == null ? void 0 : setData.id) != null ? _e : "",
2080
+ cardId,
2081
+ level: gradingStandard.level,
2082
+ justification: gradingStandard.justification,
2083
+ transcript: (_f = cardScore == null ? void 0 : cardScore.transcript) != null ? _f : "",
2084
+ audioUrl: (_g = cardScore == null ? void 0 : cardScore.audio) != null ? _g : "",
2085
+ prompt: (_h = card == null ? void 0 : card.prompt) != null ? _h : "",
2086
+ responseType: (card == null ? void 0 : card.type) === "RESPOND_WRITE" /* RESPOND_WRITE */ ? "written" : "spoken",
2087
+ type,
2088
+ dateMade: serverTimestamp()
2089
+ },
2090
+ userId
2091
+ );
2092
+ };
2093
+ useEffect2(() => {
2094
+ if (isAssignment) {
2095
+ logOpenAssignment({ assignmentId: id });
2096
+ } else {
2097
+ logOpenActivityPreview({ setId: id });
2098
+ }
2099
+ }, []);
1977
2100
  useInitActivity({
1978
- assignment: activeAssignment ?? void 0,
1979
- set: setData ?? void 0,
2101
+ assignment: activeAssignment != null ? activeAssignment : void 0,
2102
+ set: setData != null ? setData : void 0,
1980
2103
  enabled: !!setData,
1981
2104
  userId
1982
2105
  });
@@ -2002,8 +2125,7 @@ function useActivity({
2002
2125
  clear: onClearScore,
2003
2126
  submit: onSubmitScore,
2004
2127
  updateCard: handleUpdateCardScore,
2005
- logGradingStandardEntry: () => {
2006
- }
2128
+ logGradingStandardEntry
2007
2129
  }
2008
2130
  }
2009
2131
  };
@@ -2016,37 +2138,69 @@ var useInitActivity = ({
2016
2138
  }) => {
2017
2139
  const { trackActivity } = useActivityTracker({ userId });
2018
2140
  const init = () => {
2141
+ var _a, _b, _c, _d, _e;
2019
2142
  if (!enabled) return;
2020
2143
  if (!assignment) {
2021
2144
  trackActivity({
2022
- activityName: set?.name ?? "",
2145
+ activityName: (_a = set == null ? void 0 : set.name) != null ? _a : "",
2023
2146
  activityType: "set",
2024
- id: set?.id,
2025
- language: set?.language
2147
+ id: set == null ? void 0 : set.id,
2148
+ language: set == null ? void 0 : set.language
2026
2149
  });
2027
2150
  } else if (assignment.name) {
2028
2151
  trackActivity({
2029
2152
  activityName: assignment.name,
2030
2153
  activityType: assignment.isAssessment ? "assessment" : "assignment",
2031
2154
  id: assignment.id,
2032
- language: set?.language
2155
+ language: set == null ? void 0 : set.language
2033
2156
  });
2034
2157
  }
2035
- if (set?.public) {
2036
- SpeakableFirebaseFunctions?.onSetOpened?.({
2158
+ if (set == null ? void 0 : set.public) {
2159
+ (_c = (_b = SpeakableFirebaseFunctions) == null ? void 0 : _b.onSetOpened) == null ? void 0 : _c.call(_b, {
2037
2160
  setId: set.id,
2038
2161
  language: set.language
2039
2162
  });
2040
2163
  }
2041
- SpeakableFirebaseFunctions?.updateAlgoliaIndex?.({
2164
+ (_e = (_d = SpeakableFirebaseFunctions) == null ? void 0 : _d.updateAlgoliaIndex) == null ? void 0 : _e.call(_d, {
2042
2165
  updatePlays: true,
2043
- objectID: set?.id
2166
+ objectID: set == null ? void 0 : set.id
2044
2167
  });
2045
2168
  };
2046
2169
  useEffect2(() => {
2047
2170
  init();
2048
2171
  }, [set]);
2049
2172
  };
2173
+ var submitLTIScore = async ({
2174
+ maxPoints,
2175
+ score,
2176
+ SERVICE_KEY,
2177
+ lineItemId,
2178
+ lti_id
2179
+ }) => {
2180
+ var _a, _b;
2181
+ try {
2182
+ if (!SERVICE_KEY || !lineItemId || !lti_id) {
2183
+ throw new Error("Missing required LTI credentials");
2184
+ }
2185
+ const earnedPoints = score ? score / 100 * maxPoints : 0;
2186
+ const { data } = await ((_b = (_a = SpeakableFirebaseFunctions) == null ? void 0 : _a.submitLTIAssignmentScore) == null ? void 0 : _b.call(_a, {
2187
+ SERVICE_KEY,
2188
+ scoreData: {
2189
+ lineItemId,
2190
+ userId: lti_id,
2191
+ maxPoints,
2192
+ earnedPoints
2193
+ }
2194
+ }));
2195
+ return { success: true, data };
2196
+ } catch (error) {
2197
+ console.error("Failed to submit LTI score:", error);
2198
+ return {
2199
+ success: false,
2200
+ error: error instanceof Error ? error : new Error("Unknown error occurred")
2201
+ };
2202
+ }
2203
+ };
2050
2204
  export {
2051
2205
  ALLOWED_CARD_ACTIVITY_TYPES_FOR_SUMMARY,
2052
2206
  BASE_MULTIPLE_CHOICE_FIELD_VALUES,
@@ -2071,7 +2225,7 @@ export {
2071
2225
  cardsQueryKeys,
2072
2226
  createAssignmentRepo,
2073
2227
  createCardRepo,
2074
- createFsClient,
2228
+ createFsClientBase,
2075
2229
  createSetRepo,
2076
2230
  getCardFromCache,
2077
2231
  getSetFromCache,
@@ -2089,3 +2243,4 @@ export {
2089
2243
  useSet,
2090
2244
  useSpeakableApi
2091
2245
  };
2246
+ //# sourceMappingURL=index.mjs.map