@speakableio/core 0.1.105 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics-Bj2i88Zk.d.ts +89 -0
- package/dist/{assignment.model-DLMWAp0Y.d.ts → assignment.model-BRS4h8gX.d.ts} +1 -1
- package/dist/{assignment.model-Bcbxx8oI.d.mts → assignment.model-Bc61gBHl.d.ts} +5 -2
- package/dist/{assignment.model-Lu21tZCh.d.mts → assignment.model-Bm9gE2YK.d.ts} +2 -2
- package/dist/const.d.ts +3 -73
- package/dist/everything.d.ts +1348 -0
- package/dist/everything.js +3509 -0
- package/dist/everything.js.map +1 -0
- package/dist/hooks.d.ts +621 -4
- package/dist/hooks.js +1167 -39
- package/dist/hooks.js.map +1 -1
- package/dist/index.native.d.mts +2272 -27
- package/dist/index.native.d.ts +2272 -27
- package/dist/index.native.js +2915 -98
- package/dist/index.native.js.map +1 -1
- package/dist/index.native.mjs +2937 -120
- package/dist/index.native.mjs.map +1 -1
- package/dist/index.web-DNYJV_41.d.ts +469 -0
- package/dist/index.web.d.mts +2437 -6
- package/dist/index.web.d.ts +68 -2
- package/dist/index.web.js +2937 -120
- package/dist/index.web.js.map +1 -1
- package/dist/models.d.ts +2 -2
- package/dist/repos.d.ts +1 -1
- package/dist/speakable-plans-BjWWEWrQ.d.ts +72 -0
- package/dist/{const.d.mts → speakable-plans-DR1cQ6IK.d.ts} +19 -258
- package/dist/speakable-plans-Dq9nRefI.d.ts +72 -0
- package/dist/utils.d.ts +84 -2
- package/dist/utils.js +307 -1
- package/dist/utils.js.map +1 -1
- package/dist/web.constants-qmx4rGyO.d.ts +26 -0
- package/package.json +6 -62
- package/dist/analytics.cjs +0 -376
- package/dist/analytics.cjs.map +0 -1
- package/dist/assignment.constants-BIKM6fYi.d.mts +0 -32
- package/dist/card.constants-DhKFipX3.d.mts +0 -54
- package/dist/const.cjs +0 -526
- package/dist/const.cjs.map +0 -1
- package/dist/hooks.cjs +0 -1604
- package/dist/hooks.cjs.map +0 -1
- package/dist/hooks.d.mts +0 -294
- package/dist/index.web.cjs +0 -517
- package/dist/index.web.cjs.map +0 -1
- package/dist/models.cjs +0 -75
- package/dist/models.cjs.map +0 -1
- package/dist/models.d.mts +0 -56
- package/dist/notification.constants-Da4-_0kX.d.mts +0 -21
- package/dist/notification.constants-Da4-_0kX.d.ts +0 -21
- package/dist/repos.cjs +0 -486
- package/dist/repos.cjs.map +0 -1
- package/dist/repos.d.mts +0 -209
- package/dist/utils.cjs +0 -373
- package/dist/utils.cjs.map +0 -1
- package/dist/utils.d.mts +0 -39
- /package/dist/{notification.constants-B72fb734.d.mts → notification.constants-B72fb734.d.ts} +0 -0
package/dist/hooks.js
CHANGED
|
@@ -409,7 +409,10 @@ var useGoogleClassroom = () => {
|
|
|
409
409
|
}));
|
|
410
410
|
return result;
|
|
411
411
|
} catch (error) {
|
|
412
|
-
|
|
412
|
+
if (error instanceof Error) {
|
|
413
|
+
return { error: true, message: error.message };
|
|
414
|
+
}
|
|
415
|
+
return { error: true, message: "Unknown error" };
|
|
413
416
|
}
|
|
414
417
|
};
|
|
415
418
|
return {
|
|
@@ -417,6 +420,19 @@ var useGoogleClassroom = () => {
|
|
|
417
420
|
};
|
|
418
421
|
};
|
|
419
422
|
|
|
423
|
+
// src/lib/firebase/firebase-analytics/grading-standard.ts
|
|
424
|
+
var logGradingStandardLog = (data) => {
|
|
425
|
+
var _a, _b, _c;
|
|
426
|
+
if (data.courseId && data.type && data.level) {
|
|
427
|
+
(_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "handleCouresAnalyticsEvent")) == null ? void 0 : _c({
|
|
428
|
+
eventType: data.type || "custom",
|
|
429
|
+
level: data.level,
|
|
430
|
+
courseId: data.courseId
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
api.logEvent("logGradingStandard", data);
|
|
434
|
+
};
|
|
435
|
+
|
|
420
436
|
// src/constants/analytics.constants.ts
|
|
421
437
|
var ANALYTICS_EVENT_TYPES = {
|
|
422
438
|
VOICE_SUCCESS: "voice_success",
|
|
@@ -442,6 +458,12 @@ var ANALYTICS_EVENT_TYPES = {
|
|
|
442
458
|
};
|
|
443
459
|
|
|
444
460
|
// src/lib/firebase/firebase-analytics/assignment.ts
|
|
461
|
+
var logOpenAssignment = (data = {}) => {
|
|
462
|
+
api.logEvent("open_assignment", data);
|
|
463
|
+
};
|
|
464
|
+
var logOpenActivityPreview = (data = {}) => {
|
|
465
|
+
api.logEvent("open_activity_preview", data);
|
|
466
|
+
};
|
|
445
467
|
var logSubmitAssignment = (data = {}) => {
|
|
446
468
|
var _a, _b, _c;
|
|
447
469
|
(_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "handleCouresAnalyticsEvent")) == null ? void 0 : _c({
|
|
@@ -1311,8 +1333,55 @@ function useSubmitPracticeScore() {
|
|
|
1311
1333
|
};
|
|
1312
1334
|
}
|
|
1313
1335
|
|
|
1336
|
+
// src/hooks/useActivity.ts
|
|
1337
|
+
import { useEffect as useEffect2 } from "react";
|
|
1338
|
+
|
|
1339
|
+
// src/domains/sets/set.hooks.ts
|
|
1340
|
+
import { useQuery as useQuery3 } from "@tanstack/react-query";
|
|
1341
|
+
|
|
1342
|
+
// src/domains/sets/set.constants.ts
|
|
1343
|
+
var SETS_COLLECTION = "sets";
|
|
1344
|
+
var refsSetsFirestore = {
|
|
1345
|
+
allSets: SETS_COLLECTION,
|
|
1346
|
+
set: (id) => `${SETS_COLLECTION}/${id}`
|
|
1347
|
+
};
|
|
1348
|
+
|
|
1349
|
+
// src/domains/sets/services/get-set.service.ts
|
|
1350
|
+
async function _getSet({ setId }) {
|
|
1351
|
+
const response = await api.getDoc(refsSetsFirestore.set(setId));
|
|
1352
|
+
return response.data;
|
|
1353
|
+
}
|
|
1354
|
+
var getSet = withErrorHandler(_getSet, "getSet");
|
|
1355
|
+
|
|
1356
|
+
// src/domains/sets/set.hooks.ts
|
|
1357
|
+
var setsQueryKeys = {
|
|
1358
|
+
all: ["sets"],
|
|
1359
|
+
one: (params) => [...setsQueryKeys.all, params.setId]
|
|
1360
|
+
};
|
|
1361
|
+
var useSet = ({ setId, enabled }) => {
|
|
1362
|
+
return useQuery3({
|
|
1363
|
+
queryKey: setsQueryKeys.one({ setId }),
|
|
1364
|
+
queryFn: () => getSet({ setId }),
|
|
1365
|
+
enabled: setId !== void 0 && setId !== "" && enabled
|
|
1366
|
+
});
|
|
1367
|
+
};
|
|
1368
|
+
function getSetFromCache({
|
|
1369
|
+
setId,
|
|
1370
|
+
queryClient
|
|
1371
|
+
}) {
|
|
1372
|
+
if (!setId) return null;
|
|
1373
|
+
return queryClient.getQueryData(setsQueryKeys.one({ setId }));
|
|
1374
|
+
}
|
|
1375
|
+
function updateSetInCache({
|
|
1376
|
+
set,
|
|
1377
|
+
queryClient
|
|
1378
|
+
}) {
|
|
1379
|
+
const { id, ...setData } = set;
|
|
1380
|
+
queryClient.setQueryData(setsQueryKeys.one({ setId: id }), setData);
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1314
1383
|
// src/domains/cards/card.hooks.ts
|
|
1315
|
-
import { useMutation as useMutation2, useQueries, useQuery as
|
|
1384
|
+
import { useMutation as useMutation2, useQueries, useQuery as useQuery4 } from "@tanstack/react-query";
|
|
1316
1385
|
import { useMemo } from "react";
|
|
1317
1386
|
|
|
1318
1387
|
// src/domains/cards/card.constants.ts
|
|
@@ -1357,6 +1426,13 @@ var getWordHash = (word, language) => {
|
|
|
1357
1426
|
console.log("wordHash core library", wordHash);
|
|
1358
1427
|
return wordHash;
|
|
1359
1428
|
};
|
|
1429
|
+
function getPhraseLength(phrase, input) {
|
|
1430
|
+
if (Array.isArray(phrase) && phrase.includes(input)) {
|
|
1431
|
+
return phrase[phrase.indexOf(input)].split(" ").length;
|
|
1432
|
+
} else {
|
|
1433
|
+
return phrase ? phrase.split(" ").length : 0;
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1360
1436
|
|
|
1361
1437
|
// src/domains/cards/services/get-card-verification-status.service.ts
|
|
1362
1438
|
var charactarLanguages = ["zh", "ja", "ko"];
|
|
@@ -1494,7 +1570,7 @@ function updateCardInCache({
|
|
|
1494
1570
|
queryClient.setQueryData(cardsQueryKeys.one({ cardId }), card);
|
|
1495
1571
|
}
|
|
1496
1572
|
function useGetCard({ cardId, enabled = true }) {
|
|
1497
|
-
const query =
|
|
1573
|
+
const query = useQuery4({
|
|
1498
1574
|
queryKey: cardsQueryKeys.one({ cardId }),
|
|
1499
1575
|
queryFn: () => getCard({ cardId }),
|
|
1500
1576
|
enabled: enabled && !!cardId
|
|
@@ -1502,50 +1578,1095 @@ function useGetCard({ cardId, enabled = true }) {
|
|
|
1502
1578
|
return query;
|
|
1503
1579
|
}
|
|
1504
1580
|
|
|
1505
|
-
// src/
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
var refsSetsFirestore = {
|
|
1511
|
-
allSets: SETS_COLLECTION,
|
|
1512
|
-
set: (id) => `${SETS_COLLECTION}/${id}`
|
|
1581
|
+
// src/services/add-grading-standard.ts
|
|
1582
|
+
var addGradingStandardLog = async (gradingStandard, userId) => {
|
|
1583
|
+
logGradingStandardLog(gradingStandard);
|
|
1584
|
+
const path = `users/${userId}/grading_standard_logs`;
|
|
1585
|
+
await api.addDoc(path, gradingStandard);
|
|
1513
1586
|
};
|
|
1514
1587
|
|
|
1515
|
-
// src/
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1588
|
+
// src/hooks/useActivityTracker.ts
|
|
1589
|
+
import { v4 as v42 } from "uuid";
|
|
1590
|
+
function useActivityTracker({ userId }) {
|
|
1591
|
+
const trackActivity = async ({
|
|
1592
|
+
activityName,
|
|
1593
|
+
activityType,
|
|
1594
|
+
id = v42(),
|
|
1595
|
+
language = ""
|
|
1596
|
+
}) => {
|
|
1597
|
+
if (userId) {
|
|
1598
|
+
const { doc, serverTimestamp, setDoc } = api.accessHelpers();
|
|
1599
|
+
const activityRef = doc(`users/${userId}/activity/${id}`);
|
|
1600
|
+
const timestamp = serverTimestamp();
|
|
1601
|
+
await setDoc(activityRef, {
|
|
1602
|
+
name: activityName,
|
|
1603
|
+
type: activityType,
|
|
1604
|
+
lastSeen: timestamp,
|
|
1605
|
+
id,
|
|
1606
|
+
language
|
|
1607
|
+
});
|
|
1608
|
+
}
|
|
1609
|
+
};
|
|
1610
|
+
return {
|
|
1611
|
+
trackActivity
|
|
1612
|
+
};
|
|
1519
1613
|
}
|
|
1520
|
-
var getSet = withErrorHandler(_getSet, "getSet");
|
|
1521
1614
|
|
|
1522
|
-
// src/
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
return useQuery4({
|
|
1529
|
-
queryKey: setsQueryKeys.one({ setId }),
|
|
1530
|
-
queryFn: () => getSet({ setId }),
|
|
1531
|
-
enabled: setId !== void 0 && setId !== "" && enabled
|
|
1532
|
-
});
|
|
1533
|
-
};
|
|
1534
|
-
function getSetFromCache({
|
|
1535
|
-
setId,
|
|
1536
|
-
queryClient
|
|
1615
|
+
// src/hooks/useActivity.ts
|
|
1616
|
+
function useActivity({
|
|
1617
|
+
id,
|
|
1618
|
+
isAssignment,
|
|
1619
|
+
onAssignmentSubmitted,
|
|
1620
|
+
ltiData
|
|
1537
1621
|
}) {
|
|
1538
|
-
|
|
1539
|
-
|
|
1622
|
+
var _a, _b;
|
|
1623
|
+
const { queryClient, user } = useSpeakableApi();
|
|
1624
|
+
const userId = user.auth.uid;
|
|
1625
|
+
const assignmentQuery = useAssignment({
|
|
1626
|
+
assignmentId: id,
|
|
1627
|
+
userId,
|
|
1628
|
+
enabled: isAssignment
|
|
1629
|
+
});
|
|
1630
|
+
const activeAssignment = assignmentQuery.data;
|
|
1631
|
+
const setId = isAssignment ? (_a = activeAssignment == null ? void 0 : activeAssignment.setId) != null ? _a : "" : id;
|
|
1632
|
+
const querySet = useSet({ setId });
|
|
1633
|
+
const setData = querySet.data;
|
|
1634
|
+
const assignmentContent = activeAssignment == null ? void 0 : activeAssignment.content;
|
|
1635
|
+
const assignmentWeights = activeAssignment == null ? void 0 : activeAssignment.weights;
|
|
1636
|
+
const setContent = setData == null ? void 0 : setData.content;
|
|
1637
|
+
const setWeights = setData == null ? void 0 : setData.weights;
|
|
1638
|
+
const contentCardsToUse = isAssignment ? assignmentContent != null ? assignmentContent : setContent : setContent;
|
|
1639
|
+
const weightsToUse = isAssignment ? assignmentWeights != null ? assignmentWeights : setWeights : setWeights;
|
|
1640
|
+
const activityId = isAssignment ? (_b = activeAssignment == null ? void 0 : activeAssignment.id) != null ? _b : "" : setId;
|
|
1641
|
+
const { cardsObject, cardsQueries, cards } = useCards({
|
|
1642
|
+
cardIds: contentCardsToUse != null ? contentCardsToUse : [],
|
|
1643
|
+
enabled: querySet.isSuccess,
|
|
1644
|
+
asObject: true
|
|
1645
|
+
});
|
|
1646
|
+
const scoreQuery = useScore({
|
|
1647
|
+
isAssignment,
|
|
1648
|
+
activityId: id,
|
|
1649
|
+
userId,
|
|
1650
|
+
courseId: activeAssignment == null ? void 0 : activeAssignment.courseId,
|
|
1651
|
+
googleClassroomUserId: user.profile.googleClassroomUserId,
|
|
1652
|
+
enabled: isAssignment ? assignmentQuery.isSuccess : querySet.isSuccess
|
|
1653
|
+
});
|
|
1654
|
+
const { mutationUpdateScore } = useUpdateScore();
|
|
1655
|
+
const { mutationUpdateCardScore } = useUpdateCardScore({
|
|
1656
|
+
activityId,
|
|
1657
|
+
isAssignment,
|
|
1658
|
+
userId,
|
|
1659
|
+
cardIds: contentCardsToUse != null ? contentCardsToUse : [],
|
|
1660
|
+
weights: weightsToUse != null ? weightsToUse : {}
|
|
1661
|
+
});
|
|
1662
|
+
const { mutationClearScore } = useClearScore();
|
|
1663
|
+
const { submitAssignmentScore: submitAssignmentScore2 } = useSubmitAssignmentScore({
|
|
1664
|
+
onAssignmentSubmitted,
|
|
1665
|
+
studentName: user.profile.displayName
|
|
1666
|
+
});
|
|
1667
|
+
const { submitPracticeScore: submitPracticeScore2 } = useSubmitPracticeScore();
|
|
1668
|
+
const handleUpdateScore = (data) => {
|
|
1669
|
+
mutationUpdateScore.mutate({
|
|
1670
|
+
data,
|
|
1671
|
+
isAssignment,
|
|
1672
|
+
activityId,
|
|
1673
|
+
userId
|
|
1674
|
+
});
|
|
1675
|
+
};
|
|
1676
|
+
const handleUpdateCardScore = (cardId, cardScore) => {
|
|
1677
|
+
mutationUpdateCardScore.mutate({ cardId, cardScore });
|
|
1678
|
+
if (cardScore.proficiency_level) {
|
|
1679
|
+
logGradingStandardEntry({
|
|
1680
|
+
type: cardScore.proficiency_level.standardId,
|
|
1681
|
+
cardId,
|
|
1682
|
+
gradingStandard: cardScore.proficiency_level
|
|
1683
|
+
});
|
|
1684
|
+
} else if (cardScore.wida || cardScore.actfl) {
|
|
1685
|
+
logGradingStandardEntry({
|
|
1686
|
+
type: cardScore.wida ? "wida" : "actfl",
|
|
1687
|
+
cardId,
|
|
1688
|
+
gradingStandard: cardScore.wida || cardScore.actfl || { level: "", justification: "" }
|
|
1689
|
+
});
|
|
1690
|
+
}
|
|
1691
|
+
};
|
|
1692
|
+
const onClearScore = ({
|
|
1693
|
+
cardId,
|
|
1694
|
+
wasCompleted = true
|
|
1695
|
+
}) => {
|
|
1696
|
+
var _a2, _b2;
|
|
1697
|
+
const currentCard = cardsObject == null ? void 0 : cardsObject[cardId];
|
|
1698
|
+
if ((currentCard == null ? void 0 : currentCard.type) === "MULTIPLE_CHOICE" /* MULTIPLE_CHOICE */ || (currentCard == null ? void 0 : currentCard.type) === "READ_REPEAT" /* READ_REPEAT */) {
|
|
1699
|
+
return;
|
|
1700
|
+
}
|
|
1701
|
+
const queryKeys = scoreQueryKeys.byId(activityId);
|
|
1702
|
+
const activeCardScores = (_b2 = (_a2 = queryClient.getQueryData(queryKeys)) == null ? void 0 : _a2.cards) == null ? void 0 : _b2[cardId];
|
|
1703
|
+
if (activeCardScores === void 0) return;
|
|
1704
|
+
mutationClearScore.mutate({
|
|
1705
|
+
isAssignment,
|
|
1706
|
+
activityId,
|
|
1707
|
+
cardScores: activeCardScores,
|
|
1708
|
+
cardId,
|
|
1709
|
+
userId
|
|
1710
|
+
});
|
|
1711
|
+
};
|
|
1712
|
+
const onSubmitScore = async () => {
|
|
1713
|
+
var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
|
|
1714
|
+
try {
|
|
1715
|
+
let results;
|
|
1716
|
+
if (isAssignment) {
|
|
1717
|
+
const cardScores = ((_a2 = scoreQuery.data) == null ? void 0 : _a2.cards) || {};
|
|
1718
|
+
const hasPendingReview = Object.values(cardScores).some(
|
|
1719
|
+
(cardScore) => cardScore.status === "pending_review"
|
|
1720
|
+
);
|
|
1721
|
+
results = await submitAssignmentScore2({
|
|
1722
|
+
assignment: {
|
|
1723
|
+
id: (_c = (_b2 = assignmentQuery.data) == null ? void 0 : _b2.id) != null ? _c : "",
|
|
1724
|
+
name: (_e = (_d = assignmentQuery.data) == null ? void 0 : _d.name) != null ? _e : "",
|
|
1725
|
+
owners: (_g = (_f = assignmentQuery.data) == null ? void 0 : _f.owners) != null ? _g : [],
|
|
1726
|
+
courseId: (_i = (_h = assignmentQuery.data) == null ? void 0 : _h.courseId) != null ? _i : "",
|
|
1727
|
+
courseWorkId: (_k = (_j = assignmentQuery.data) == null ? void 0 : _j.courseWorkId) != null ? _k : "",
|
|
1728
|
+
isAssessment: (_m = (_l = assignmentQuery.data) == null ? void 0 : _l.isAssessment) != null ? _m : false,
|
|
1729
|
+
maxPoints: (_o = (_n = assignmentQuery.data) == null ? void 0 : _n.maxPoints) != null ? _o : 0
|
|
1730
|
+
},
|
|
1731
|
+
userId,
|
|
1732
|
+
cardIds: contentCardsToUse != null ? contentCardsToUse : [],
|
|
1733
|
+
scores: scoreQuery.data,
|
|
1734
|
+
weights: weightsToUse != null ? weightsToUse : {},
|
|
1735
|
+
status: hasPendingReview ? "PENDING_REVIEW" : "FINALIZED"
|
|
1736
|
+
});
|
|
1737
|
+
if ((_p = assignmentQuery.data) == null ? void 0 : _p.ltiDeeplink) {
|
|
1738
|
+
submitLTIScore({
|
|
1739
|
+
maxPoints: (_q = assignmentQuery.data) == null ? void 0 : _q.maxPoints,
|
|
1740
|
+
score: (_s = (_r = scoreQuery.data) == null ? void 0 : _r.score) != null ? _s : 0,
|
|
1741
|
+
SERVICE_KEY: (_t = ltiData == null ? void 0 : ltiData.serviceKey) != null ? _t : "",
|
|
1742
|
+
lineItemId: (_u = ltiData == null ? void 0 : ltiData.lineItemId) != null ? _u : "",
|
|
1743
|
+
lti_id: (_v = ltiData == null ? void 0 : ltiData.lti_id) != null ? _v : ""
|
|
1744
|
+
});
|
|
1745
|
+
}
|
|
1746
|
+
} else {
|
|
1747
|
+
results = await submitPracticeScore2({
|
|
1748
|
+
setId: (_x = (_w = querySet.data) == null ? void 0 : _w.id) != null ? _x : "",
|
|
1749
|
+
userId,
|
|
1750
|
+
scores: scoreQuery.data
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
return results;
|
|
1754
|
+
} catch (error) {
|
|
1755
|
+
return {
|
|
1756
|
+
success: false,
|
|
1757
|
+
error
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
const logGradingStandardEntry = ({
|
|
1762
|
+
cardId,
|
|
1763
|
+
gradingStandard,
|
|
1764
|
+
type
|
|
1765
|
+
}) => {
|
|
1766
|
+
var _a2, _b2, _c, _d, _e, _f, _g, _h, _i;
|
|
1767
|
+
const card = cardsObject == null ? void 0 : cardsObject[cardId];
|
|
1768
|
+
const scoresObject = queryClient.getQueryData(scoreQueryKeys.byId(activityId));
|
|
1769
|
+
const cardScore = (_a2 = scoresObject == null ? void 0 : scoresObject.cards) == null ? void 0 : _a2[cardId];
|
|
1770
|
+
const serverTimestamp = api.helpers.serverTimestamp;
|
|
1771
|
+
addGradingStandardLog(
|
|
1772
|
+
{
|
|
1773
|
+
assignmentId: (_b2 = activeAssignment == null ? void 0 : activeAssignment.id) != null ? _b2 : "",
|
|
1774
|
+
courseId: (_c = activeAssignment == null ? void 0 : activeAssignment.courseId) != null ? _c : "",
|
|
1775
|
+
teacherId: (_d = activeAssignment == null ? void 0 : activeAssignment.owners[0]) != null ? _d : "",
|
|
1776
|
+
setId: (_e = setData == null ? void 0 : setData.id) != null ? _e : "",
|
|
1777
|
+
cardId,
|
|
1778
|
+
level: gradingStandard.level,
|
|
1779
|
+
justification: gradingStandard.justification,
|
|
1780
|
+
transcript: (_f = cardScore == null ? void 0 : cardScore.transcript) != null ? _f : "",
|
|
1781
|
+
audioUrl: (_g = cardScore == null ? void 0 : cardScore.audio) != null ? _g : "",
|
|
1782
|
+
prompt: (_h = card == null ? void 0 : card.prompt) != null ? _h : "",
|
|
1783
|
+
responseType: (card == null ? void 0 : card.type) === "RESPOND_WRITE" /* RESPOND_WRITE */ ? "written" : "spoken",
|
|
1784
|
+
type,
|
|
1785
|
+
dateMade: serverTimestamp(),
|
|
1786
|
+
language: (_i = card == null ? void 0 : card.language) != null ? _i : ""
|
|
1787
|
+
},
|
|
1788
|
+
userId
|
|
1789
|
+
);
|
|
1790
|
+
};
|
|
1791
|
+
useEffect2(() => {
|
|
1792
|
+
if (isAssignment) {
|
|
1793
|
+
logOpenAssignment({ assignmentId: id });
|
|
1794
|
+
} else {
|
|
1795
|
+
logOpenActivityPreview({ setId: id });
|
|
1796
|
+
}
|
|
1797
|
+
}, []);
|
|
1798
|
+
useInitActivity({
|
|
1799
|
+
assignment: activeAssignment != null ? activeAssignment : void 0,
|
|
1800
|
+
set: setData != null ? setData : void 0,
|
|
1801
|
+
enabled: !!setData,
|
|
1802
|
+
userId
|
|
1803
|
+
});
|
|
1804
|
+
return {
|
|
1805
|
+
set: {
|
|
1806
|
+
data: setData,
|
|
1807
|
+
query: querySet
|
|
1808
|
+
},
|
|
1809
|
+
cards: {
|
|
1810
|
+
data: cardsObject,
|
|
1811
|
+
query: cardsQueries,
|
|
1812
|
+
cardsArray: cards
|
|
1813
|
+
},
|
|
1814
|
+
assignment: {
|
|
1815
|
+
data: isAssignment ? activeAssignment : void 0,
|
|
1816
|
+
query: assignmentQuery
|
|
1817
|
+
},
|
|
1818
|
+
scores: {
|
|
1819
|
+
data: scoreQuery.data,
|
|
1820
|
+
query: scoreQuery,
|
|
1821
|
+
actions: {
|
|
1822
|
+
update: handleUpdateScore,
|
|
1823
|
+
clear: onClearScore,
|
|
1824
|
+
submit: onSubmitScore,
|
|
1825
|
+
updateCard: handleUpdateCardScore,
|
|
1826
|
+
logGradingStandardEntry
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
};
|
|
1540
1830
|
}
|
|
1541
|
-
|
|
1831
|
+
var useInitActivity = ({
|
|
1832
|
+
assignment,
|
|
1542
1833
|
set,
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1834
|
+
enabled,
|
|
1835
|
+
userId
|
|
1836
|
+
}) => {
|
|
1837
|
+
const { trackActivity } = useActivityTracker({ userId });
|
|
1838
|
+
const init = () => {
|
|
1839
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1840
|
+
if (!enabled) return;
|
|
1841
|
+
if (!assignment) {
|
|
1842
|
+
trackActivity({
|
|
1843
|
+
activityName: (_a = set == null ? void 0 : set.name) != null ? _a : "",
|
|
1844
|
+
activityType: "set",
|
|
1845
|
+
id: set == null ? void 0 : set.id,
|
|
1846
|
+
language: set == null ? void 0 : set.language
|
|
1847
|
+
});
|
|
1848
|
+
} else if (assignment.name) {
|
|
1849
|
+
trackActivity({
|
|
1850
|
+
activityName: assignment.name,
|
|
1851
|
+
activityType: assignment.isAssessment ? "assessment" : "assignment",
|
|
1852
|
+
id: assignment.id,
|
|
1853
|
+
language: set == null ? void 0 : set.language
|
|
1854
|
+
});
|
|
1855
|
+
}
|
|
1856
|
+
if (set == null ? void 0 : set.public) {
|
|
1857
|
+
(_d = (_c = (_b = api).httpsCallable) == null ? void 0 : _c.call(_b, "onSetOpened")) == null ? void 0 : _d({
|
|
1858
|
+
setId: set.id,
|
|
1859
|
+
language: set.language
|
|
1860
|
+
});
|
|
1861
|
+
}
|
|
1862
|
+
(_g = (_f = (_e = api).httpsCallable) == null ? void 0 : _f.call(_e, "updateAlgoliaIndex")) == null ? void 0 : _g({
|
|
1863
|
+
updatePlays: true,
|
|
1864
|
+
objectID: set == null ? void 0 : set.id
|
|
1865
|
+
});
|
|
1866
|
+
};
|
|
1867
|
+
useEffect2(() => {
|
|
1868
|
+
init();
|
|
1869
|
+
}, [set]);
|
|
1870
|
+
};
|
|
1871
|
+
var submitLTIScore = async ({
|
|
1872
|
+
maxPoints,
|
|
1873
|
+
score,
|
|
1874
|
+
SERVICE_KEY,
|
|
1875
|
+
lineItemId,
|
|
1876
|
+
lti_id
|
|
1877
|
+
}) => {
|
|
1878
|
+
var _a, _b, _c;
|
|
1879
|
+
try {
|
|
1880
|
+
if (!SERVICE_KEY || !lineItemId || !lti_id) {
|
|
1881
|
+
throw new Error("Missing required LTI credentials");
|
|
1882
|
+
}
|
|
1883
|
+
const earnedPoints = score ? score / 100 * maxPoints : 0;
|
|
1884
|
+
const { data } = await ((_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "submitLTIAssignmentScore")) == null ? void 0 : _c({
|
|
1885
|
+
SERVICE_KEY,
|
|
1886
|
+
scoreData: {
|
|
1887
|
+
lineItemId,
|
|
1888
|
+
userId: lti_id,
|
|
1889
|
+
maxPoints,
|
|
1890
|
+
earnedPoints
|
|
1891
|
+
}
|
|
1892
|
+
}));
|
|
1893
|
+
return { success: true, data };
|
|
1894
|
+
} catch (error) {
|
|
1895
|
+
console.error("Failed to submit LTI score:", error);
|
|
1896
|
+
return {
|
|
1897
|
+
success: false,
|
|
1898
|
+
error: error instanceof Error ? error : new Error("Unknown error occurred")
|
|
1899
|
+
};
|
|
1900
|
+
}
|
|
1901
|
+
};
|
|
1902
|
+
|
|
1903
|
+
// src/hooks/useActivityFeedbackAccess.ts
|
|
1904
|
+
import { useQuery as useQuery5 } from "@tanstack/react-query";
|
|
1905
|
+
var activityFeedbackAccessQueryKeys = {
|
|
1906
|
+
activityFeedbackAccess: (args) => ["activityFeedbackAccess", ...Object.values(args)]
|
|
1907
|
+
};
|
|
1908
|
+
var useActivityFeedbackAccess = ({
|
|
1909
|
+
aiEnabled = false,
|
|
1910
|
+
isActivityRoute = false
|
|
1911
|
+
}) => {
|
|
1912
|
+
var _a, _b, _c;
|
|
1913
|
+
const { user } = useSpeakableApi();
|
|
1914
|
+
const uid = user.auth.uid;
|
|
1915
|
+
const isTeacher = (_a = user.profile) == null ? void 0 : _a.isTeacher;
|
|
1916
|
+
const isStudent = (_b = user.profile) == null ? void 0 : _b.isStudent;
|
|
1917
|
+
const userRoles = ((_c = user.profile) == null ? void 0 : _c.roles) || [];
|
|
1918
|
+
const query = useQuery5({
|
|
1919
|
+
queryKey: activityFeedbackAccessQueryKeys.activityFeedbackAccess({
|
|
1920
|
+
aiEnabled,
|
|
1921
|
+
isActivityRoute
|
|
1922
|
+
}),
|
|
1923
|
+
queryFn: async () => {
|
|
1924
|
+
var _a2, _b2, _c2;
|
|
1925
|
+
if (!uid) {
|
|
1926
|
+
return {
|
|
1927
|
+
canAccessFeedback: false,
|
|
1928
|
+
reason: "Missing user ID",
|
|
1929
|
+
isUnlimited: false,
|
|
1930
|
+
accessType: "none"
|
|
1931
|
+
};
|
|
1932
|
+
}
|
|
1933
|
+
try {
|
|
1934
|
+
if (aiEnabled) {
|
|
1935
|
+
return {
|
|
1936
|
+
canAccessFeedback: true,
|
|
1937
|
+
reason: "AI feedback enabled",
|
|
1938
|
+
isUnlimited: true,
|
|
1939
|
+
accessType: "ai_enabled"
|
|
1940
|
+
};
|
|
1941
|
+
}
|
|
1942
|
+
if (isTeacher || userRoles.includes("ADMIN")) {
|
|
1943
|
+
return {
|
|
1944
|
+
canAccessFeedback: true,
|
|
1945
|
+
reason: "Teacher preview access",
|
|
1946
|
+
isUnlimited: true,
|
|
1947
|
+
accessType: "teacher_preview"
|
|
1948
|
+
};
|
|
1949
|
+
}
|
|
1950
|
+
if (isStudent && isActivityRoute) {
|
|
1951
|
+
try {
|
|
1952
|
+
const result = await ((_c2 = (_b2 = (_a2 = api).httpsCallable) == null ? void 0 : _b2.call(_a2, "checkStudentTeacherPlan")) == null ? void 0 : _c2({
|
|
1953
|
+
studentId: uid
|
|
1954
|
+
}));
|
|
1955
|
+
const planCheckResult = result.data;
|
|
1956
|
+
if (planCheckResult.canAccessFeedback) {
|
|
1957
|
+
return {
|
|
1958
|
+
canAccessFeedback: true,
|
|
1959
|
+
reason: planCheckResult.reason || "Student access via teacher with active plan",
|
|
1960
|
+
isUnlimited: planCheckResult.hasTeacherWithUnlimitedAccess,
|
|
1961
|
+
accessType: "student_with_teacher_plan"
|
|
1962
|
+
};
|
|
1963
|
+
} else {
|
|
1964
|
+
return {
|
|
1965
|
+
canAccessFeedback: false,
|
|
1966
|
+
reason: planCheckResult.reason || "No teacher with active plan found",
|
|
1967
|
+
isUnlimited: false,
|
|
1968
|
+
accessType: "none"
|
|
1969
|
+
};
|
|
1970
|
+
}
|
|
1971
|
+
} catch (error) {
|
|
1972
|
+
console.error("Error checking student teacher plan:", error);
|
|
1973
|
+
return {
|
|
1974
|
+
canAccessFeedback: false,
|
|
1975
|
+
reason: "Error checking teacher plans",
|
|
1976
|
+
isUnlimited: false,
|
|
1977
|
+
accessType: "none"
|
|
1978
|
+
};
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
return {
|
|
1982
|
+
canAccessFeedback: false,
|
|
1983
|
+
reason: "No access permissions found for current context",
|
|
1984
|
+
isUnlimited: false,
|
|
1985
|
+
accessType: "none"
|
|
1986
|
+
};
|
|
1987
|
+
} catch (error) {
|
|
1988
|
+
console.error("Error checking activity feedback access:", error);
|
|
1989
|
+
return {
|
|
1990
|
+
canAccessFeedback: false,
|
|
1991
|
+
reason: "Error checking access permissions",
|
|
1992
|
+
isUnlimited: false,
|
|
1993
|
+
accessType: "none"
|
|
1994
|
+
};
|
|
1995
|
+
}
|
|
1996
|
+
},
|
|
1997
|
+
enabled: !!uid,
|
|
1998
|
+
staleTime: 5 * 60 * 1e3,
|
|
1999
|
+
// 5 minutes
|
|
2000
|
+
gcTime: 10 * 60 * 1e3
|
|
2001
|
+
// 10 minutes
|
|
2002
|
+
});
|
|
2003
|
+
return {
|
|
2004
|
+
...query
|
|
2005
|
+
};
|
|
2006
|
+
};
|
|
2007
|
+
|
|
2008
|
+
// src/constants/all-langs.json
|
|
2009
|
+
var all_langs_default = {
|
|
2010
|
+
af: "Afrikaans",
|
|
2011
|
+
sq: "Albanian",
|
|
2012
|
+
am: "Amharic",
|
|
2013
|
+
ar: "Arabic",
|
|
2014
|
+
hy: "Armenian",
|
|
2015
|
+
az: "Azerbaijani",
|
|
2016
|
+
eu: "Basque",
|
|
2017
|
+
be: "Belarusian",
|
|
2018
|
+
bn: "Bengali",
|
|
2019
|
+
bs: "Bosnian",
|
|
2020
|
+
bg: "Bulgarian",
|
|
2021
|
+
ca: "Catalan",
|
|
2022
|
+
ceb: "Cebuano",
|
|
2023
|
+
zh: "Chinese",
|
|
2024
|
+
co: "Corsican",
|
|
2025
|
+
hr: "Croatian",
|
|
2026
|
+
cs: "Czech",
|
|
2027
|
+
da: "Danish",
|
|
2028
|
+
nl: "Dutch",
|
|
2029
|
+
en: "English",
|
|
2030
|
+
eo: "Esperanto",
|
|
2031
|
+
et: "Estonian",
|
|
2032
|
+
fi: "Finnish",
|
|
2033
|
+
fr: "French",
|
|
2034
|
+
fy: "Frisian",
|
|
2035
|
+
gl: "Galician",
|
|
2036
|
+
ka: "Georgian",
|
|
2037
|
+
de: "German",
|
|
2038
|
+
el: "Greek",
|
|
2039
|
+
gu: "Gujarati",
|
|
2040
|
+
ht: "Haitian Creole",
|
|
2041
|
+
ha: "Hausa",
|
|
2042
|
+
haw: "Hawaiian",
|
|
2043
|
+
he: "Hebrew",
|
|
2044
|
+
hi: "Hindi",
|
|
2045
|
+
hmn: "Hmong",
|
|
2046
|
+
hu: "Hungarian",
|
|
2047
|
+
is: "Icelandic",
|
|
2048
|
+
ig: "Igbo",
|
|
2049
|
+
id: "Indonesian",
|
|
2050
|
+
ga: "Irish",
|
|
2051
|
+
it: "Italian",
|
|
2052
|
+
ja: "Japanese",
|
|
2053
|
+
jv: "Javanese",
|
|
2054
|
+
kn: "Kannada",
|
|
2055
|
+
kk: "Kazakh",
|
|
2056
|
+
km: "Khmer",
|
|
2057
|
+
ko: "Korean",
|
|
2058
|
+
ku: "Kurdish",
|
|
2059
|
+
ky: "Kyrgyz",
|
|
2060
|
+
lo: "Lao",
|
|
2061
|
+
la: "Latin",
|
|
2062
|
+
lv: "Latvian",
|
|
2063
|
+
lt: "Lithuanian",
|
|
2064
|
+
lb: "Luxembourgish",
|
|
2065
|
+
mk: "Macedonian",
|
|
2066
|
+
mg: "Malagasy",
|
|
2067
|
+
ms: "Malay",
|
|
2068
|
+
ml: "Malayalam",
|
|
2069
|
+
mt: "Maltese",
|
|
2070
|
+
mi: "Maori",
|
|
2071
|
+
mr: "Marathi",
|
|
2072
|
+
mn: "Mongolian",
|
|
2073
|
+
my: "Myanmar (Burmese)",
|
|
2074
|
+
ne: "Nepali",
|
|
2075
|
+
no: "Norwegian",
|
|
2076
|
+
ny: "Nyanja (Chichewa)",
|
|
2077
|
+
ps: "Pashto",
|
|
2078
|
+
fa: "Persian",
|
|
2079
|
+
pl: "Polish",
|
|
2080
|
+
pt: "Portuguese",
|
|
2081
|
+
pa: "Punjabi",
|
|
2082
|
+
ro: "Romanian",
|
|
2083
|
+
ru: "Russian",
|
|
2084
|
+
sm: "Samoan",
|
|
2085
|
+
gd: "Scots Gaelic",
|
|
2086
|
+
sr: "Serbian",
|
|
2087
|
+
st: "Sesotho",
|
|
2088
|
+
sn: "Shona",
|
|
2089
|
+
sd: "Sindhi",
|
|
2090
|
+
si: "Sinhala (Sinhalese)",
|
|
2091
|
+
sk: "Slovak",
|
|
2092
|
+
sl: "Slovenian",
|
|
2093
|
+
so: "Somali",
|
|
2094
|
+
es: "Spanish",
|
|
2095
|
+
su: "Sundanese",
|
|
2096
|
+
sw: "Swahili",
|
|
2097
|
+
sv: "Swedish",
|
|
2098
|
+
tl: "Tagalog (Filipino)",
|
|
2099
|
+
tg: "Tajik",
|
|
2100
|
+
ta: "Tamil",
|
|
2101
|
+
te: "Telugu",
|
|
2102
|
+
th: "Thai",
|
|
2103
|
+
tr: "Turkish",
|
|
2104
|
+
uk: "Ukrainian",
|
|
2105
|
+
ur: "Urdu",
|
|
2106
|
+
uz: "Uzbek",
|
|
2107
|
+
vi: "Vietnamese",
|
|
2108
|
+
cy: "Welsh",
|
|
2109
|
+
xh: "Xhosa",
|
|
2110
|
+
yi: "Yiddish",
|
|
2111
|
+
yo: "Yoruba",
|
|
2112
|
+
zu: "Zulu"
|
|
2113
|
+
};
|
|
2114
|
+
|
|
2115
|
+
// src/utils/ai/get-respond-card-tool.ts
|
|
2116
|
+
var getRespondCardTool = ({
|
|
2117
|
+
language,
|
|
2118
|
+
standard = "actfl"
|
|
2119
|
+
}) => {
|
|
2120
|
+
const lang = all_langs_default[language] || "English";
|
|
2121
|
+
const tool = {
|
|
2122
|
+
tool_choice: {
|
|
2123
|
+
type: "function",
|
|
2124
|
+
function: { name: "get_feedback" }
|
|
2125
|
+
},
|
|
2126
|
+
tools: [
|
|
2127
|
+
{
|
|
2128
|
+
type: "function",
|
|
2129
|
+
function: {
|
|
2130
|
+
name: "get_feedback",
|
|
2131
|
+
description: "Get feedback on a student's response",
|
|
2132
|
+
parameters: {
|
|
2133
|
+
type: "object",
|
|
2134
|
+
required: [
|
|
2135
|
+
"success",
|
|
2136
|
+
"score",
|
|
2137
|
+
"score_justification",
|
|
2138
|
+
"errors",
|
|
2139
|
+
"improvedResponse",
|
|
2140
|
+
"compliments"
|
|
2141
|
+
],
|
|
2142
|
+
properties: {
|
|
2143
|
+
success: {
|
|
2144
|
+
type: "boolean",
|
|
2145
|
+
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."
|
|
2146
|
+
},
|
|
2147
|
+
errors: {
|
|
2148
|
+
type: "array",
|
|
2149
|
+
items: {
|
|
2150
|
+
type: "object",
|
|
2151
|
+
required: ["error", "grammar_error_type", "correction", "justification"],
|
|
2152
|
+
properties: {
|
|
2153
|
+
error: {
|
|
2154
|
+
type: "string",
|
|
2155
|
+
description: "The grammatical error in the student's response."
|
|
2156
|
+
},
|
|
2157
|
+
correction: {
|
|
2158
|
+
type: "string",
|
|
2159
|
+
description: "The suggested correction to the error"
|
|
2160
|
+
},
|
|
2161
|
+
justification: {
|
|
2162
|
+
type: "string",
|
|
2163
|
+
description: `An explanation of the rationale behind the suggested correction. WRITE THIS IN ${lang}!`
|
|
2164
|
+
},
|
|
2165
|
+
grammar_error_type: {
|
|
2166
|
+
type: "string",
|
|
2167
|
+
enum: [
|
|
2168
|
+
"subjVerbAgree",
|
|
2169
|
+
"tenseErrors",
|
|
2170
|
+
"articleMisuse",
|
|
2171
|
+
"prepositionErrors",
|
|
2172
|
+
"adjNounAgree",
|
|
2173
|
+
"pronounErrors",
|
|
2174
|
+
"wordOrder",
|
|
2175
|
+
"verbConjugation",
|
|
2176
|
+
"pluralization",
|
|
2177
|
+
"negationErrors",
|
|
2178
|
+
"modalVerbMisuse",
|
|
2179
|
+
"relativeClause",
|
|
2180
|
+
"auxiliaryVerb",
|
|
2181
|
+
"complexSentenceAgreement",
|
|
2182
|
+
"idiomaticExpression",
|
|
2183
|
+
"registerInconsistency",
|
|
2184
|
+
"voiceMisuse"
|
|
2185
|
+
],
|
|
2186
|
+
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"
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
},
|
|
2190
|
+
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."
|
|
2191
|
+
},
|
|
2192
|
+
compliments: {
|
|
2193
|
+
type: "array",
|
|
2194
|
+
items: {
|
|
2195
|
+
type: "string"
|
|
2196
|
+
},
|
|
2197
|
+
description: `An array of strings, each representing something the student did well. Each string should be WRITTEN IN ${lang}!`
|
|
2198
|
+
},
|
|
2199
|
+
improvedResponse: {
|
|
2200
|
+
type: "string",
|
|
2201
|
+
description: "An improved response with proper grammar and more detail, if applicable."
|
|
2202
|
+
},
|
|
2203
|
+
score: {
|
|
2204
|
+
type: "number",
|
|
2205
|
+
description: "A score between 0 and 100, reflecting the overall quality of the response"
|
|
2206
|
+
},
|
|
2207
|
+
score_justification: {
|
|
2208
|
+
type: "string",
|
|
2209
|
+
description: "An explanation of the rationale behind the assigned score, considering both accuracy and fluency"
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
]
|
|
2216
|
+
};
|
|
2217
|
+
if (standard === "wida") {
|
|
2218
|
+
const wida_level = {
|
|
2219
|
+
type: "number",
|
|
2220
|
+
enum: [1, 2, 3, 4, 5, 6],
|
|
2221
|
+
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
|
|
2222
|
+
|
|
2223
|
+
1 - Entering
|
|
2224
|
+
2 - Emerging
|
|
2225
|
+
3 - Developing
|
|
2226
|
+
4 - Expanding
|
|
2227
|
+
5 - Bridging
|
|
2228
|
+
6 - Reaching
|
|
2229
|
+
|
|
2230
|
+
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.
|
|
2231
|
+
`
|
|
2232
|
+
};
|
|
2233
|
+
const wida_justification = {
|
|
2234
|
+
type: "string",
|
|
2235
|
+
description: `An explanation of the rationale behind the assigned WIDA level of the response, considering both accuracy and fluency. WRITE THIS IN ENGLISH!`
|
|
2236
|
+
};
|
|
2237
|
+
tool.tools[0].function.parameters.required.push("wida_level");
|
|
2238
|
+
tool.tools[0].function.parameters.required.push("wida_justification");
|
|
2239
|
+
tool.tools[0].function.parameters.properties.wida_level = wida_level;
|
|
2240
|
+
tool.tools[0].function.parameters.properties.wida_justification = wida_justification;
|
|
2241
|
+
} else {
|
|
2242
|
+
const actfl_level = {
|
|
2243
|
+
type: "string",
|
|
2244
|
+
enum: ["NL", "NM", "NH", "IL", "IM", "IH", "AL", "AM", "AH", "S", "D"],
|
|
2245
|
+
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"
|
|
2246
|
+
};
|
|
2247
|
+
const actfl_justification = {
|
|
2248
|
+
type: "string",
|
|
2249
|
+
description: "An explanation of the rationale behind the assigned ACTFL level, considering both accuracy and fluency"
|
|
2250
|
+
};
|
|
2251
|
+
tool.tools[0].function.parameters.required.push("actfl_level");
|
|
2252
|
+
tool.tools[0].function.parameters.required.push("actfl_justification");
|
|
2253
|
+
tool.tools[0].function.parameters.properties.actfl_level = actfl_level;
|
|
2254
|
+
tool.tools[0].function.parameters.properties.actfl_justification = actfl_justification;
|
|
2255
|
+
}
|
|
2256
|
+
return tool;
|
|
2257
|
+
};
|
|
2258
|
+
|
|
2259
|
+
// src/hooks/useOpenAI.ts
|
|
2260
|
+
var useBaseOpenAI = ({
|
|
2261
|
+
onTranscriptSuccess,
|
|
2262
|
+
onTranscriptError,
|
|
2263
|
+
onCompletionSuccess,
|
|
2264
|
+
onCompletionError,
|
|
2265
|
+
aiEnabled,
|
|
2266
|
+
submitAudioResponse,
|
|
2267
|
+
uploadAudioAndGetTranscript,
|
|
2268
|
+
onGetAudioUrlAndTranscript
|
|
2269
|
+
}) => {
|
|
2270
|
+
const { user, queryClient } = useSpeakableApi();
|
|
2271
|
+
const currentUserId = user.auth.uid;
|
|
2272
|
+
const { data: feedbackAccess } = useActivityFeedbackAccess({
|
|
2273
|
+
aiEnabled
|
|
2274
|
+
});
|
|
2275
|
+
const getTranscript = async (audioUrl, language) => {
|
|
2276
|
+
var _a, _b;
|
|
2277
|
+
try {
|
|
2278
|
+
const getAssemblyAITranscript = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "transcribeAssemblyAIAudio");
|
|
2279
|
+
const response = await (getAssemblyAITranscript == null ? void 0 : getAssemblyAITranscript({
|
|
2280
|
+
audioUrl,
|
|
2281
|
+
language
|
|
2282
|
+
}));
|
|
2283
|
+
const transcript = response == null ? void 0 : response.data;
|
|
2284
|
+
return transcript;
|
|
2285
|
+
} catch (error) {
|
|
2286
|
+
console.log("error", error);
|
|
2287
|
+
onTranscriptError({
|
|
2288
|
+
type: "TRANSCRIPT",
|
|
2289
|
+
message: (error == null ? void 0 : error.message) || "Error getting transcript"
|
|
2290
|
+
});
|
|
2291
|
+
throw new Error(error);
|
|
2292
|
+
}
|
|
2293
|
+
};
|
|
2294
|
+
const getFreeResponseCompletion = async (messages, isFreeResponse, feedbackLanguage, gradingStandard = "actfl") => {
|
|
2295
|
+
var _a, _b, _c, _d, _e;
|
|
2296
|
+
const responseTool = getRespondCardTool({
|
|
2297
|
+
language: feedbackLanguage,
|
|
2298
|
+
standard: gradingStandard
|
|
2299
|
+
});
|
|
2300
|
+
try {
|
|
2301
|
+
const createChatCompletion = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "createChatCompletion");
|
|
2302
|
+
const {
|
|
2303
|
+
data: {
|
|
2304
|
+
response,
|
|
2305
|
+
prompt_tokens = 0,
|
|
2306
|
+
completion_tokens = 0,
|
|
2307
|
+
success: aiSuccess = false
|
|
2308
|
+
// the AI was able to generate a response
|
|
2309
|
+
}
|
|
2310
|
+
} = await (createChatCompletion == null ? void 0 : createChatCompletion({
|
|
2311
|
+
chat: {
|
|
2312
|
+
model: isFreeResponse ? "gpt-4-1106-preview" : "gpt-3.5-turbo-1106",
|
|
2313
|
+
messages,
|
|
2314
|
+
temperature: 0.7,
|
|
2315
|
+
...responseTool
|
|
2316
|
+
},
|
|
2317
|
+
type: isFreeResponse ? "LONG_RESPONSE" : "SHORT_RESPONSE"
|
|
2318
|
+
}));
|
|
2319
|
+
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) || "{}");
|
|
2320
|
+
const result = {
|
|
2321
|
+
...functionArguments,
|
|
2322
|
+
prompt_tokens,
|
|
2323
|
+
completion_tokens,
|
|
2324
|
+
aiSuccess
|
|
2325
|
+
};
|
|
2326
|
+
onCompletionSuccess(result);
|
|
2327
|
+
return result;
|
|
2328
|
+
} catch (error) {
|
|
2329
|
+
onCompletionError({
|
|
2330
|
+
type: "COMPLETION",
|
|
2331
|
+
message: (error == null ? void 0 : error.message) || "Error getting completion"
|
|
2332
|
+
});
|
|
2333
|
+
throw new Error(error);
|
|
2334
|
+
}
|
|
2335
|
+
};
|
|
2336
|
+
const getFeedback = async ({
|
|
2337
|
+
cardId,
|
|
2338
|
+
language = "en",
|
|
2339
|
+
// required
|
|
2340
|
+
writtenResponse = null,
|
|
2341
|
+
// if the type = RESPOND_WRITE
|
|
2342
|
+
audio = null,
|
|
2343
|
+
autoGrade = true,
|
|
2344
|
+
file = null
|
|
2345
|
+
}) => {
|
|
2346
|
+
try {
|
|
2347
|
+
if (!(feedbackAccess == null ? void 0 : feedbackAccess.canAccessFeedback)) {
|
|
2348
|
+
const result = {
|
|
2349
|
+
noFeedbackAvailable: true,
|
|
2350
|
+
success: true,
|
|
2351
|
+
reason: (feedbackAccess == null ? void 0 : feedbackAccess.reason) || "No feedback access",
|
|
2352
|
+
accessType: (feedbackAccess == null ? void 0 : feedbackAccess.accessType) || "none"
|
|
2353
|
+
};
|
|
2354
|
+
onCompletionSuccess(result);
|
|
2355
|
+
return result;
|
|
2356
|
+
}
|
|
2357
|
+
let transcript;
|
|
2358
|
+
let audioUrl = void 0;
|
|
2359
|
+
if (writtenResponse) {
|
|
2360
|
+
transcript = writtenResponse;
|
|
2361
|
+
onTranscriptSuccess(writtenResponse);
|
|
2362
|
+
} else if (typeof audio === "string" && file) {
|
|
2363
|
+
if (feedbackAccess == null ? void 0 : feedbackAccess.canAccessFeedback) {
|
|
2364
|
+
transcript = await getTranscript(audio, language);
|
|
2365
|
+
audioUrl = audio;
|
|
2366
|
+
onTranscriptSuccess(transcript);
|
|
2367
|
+
} else {
|
|
2368
|
+
console.info(
|
|
2369
|
+
`Transcript not available: ${(feedbackAccess == null ? void 0 : feedbackAccess.reason) || "No feedback access"}`
|
|
2370
|
+
);
|
|
2371
|
+
}
|
|
2372
|
+
} else {
|
|
2373
|
+
const response = await uploadAudioAndGetTranscript(audio || "", language);
|
|
2374
|
+
transcript = response.transcript;
|
|
2375
|
+
audioUrl = response.audioUrl;
|
|
2376
|
+
}
|
|
2377
|
+
onGetAudioUrlAndTranscript == null ? void 0 : onGetAudioUrlAndTranscript({ transcript, audioUrl });
|
|
2378
|
+
if (feedbackAccess == null ? void 0 : feedbackAccess.canAccessFeedback) {
|
|
2379
|
+
const results = await getAIResponse({
|
|
2380
|
+
cardId,
|
|
2381
|
+
transcript: transcript || ""
|
|
2382
|
+
});
|
|
2383
|
+
let output = results;
|
|
2384
|
+
if (!autoGrade) {
|
|
2385
|
+
output = {
|
|
2386
|
+
...output,
|
|
2387
|
+
noFeedbackAvailable: true,
|
|
2388
|
+
success: true
|
|
2389
|
+
};
|
|
2390
|
+
}
|
|
2391
|
+
onCompletionSuccess(output);
|
|
2392
|
+
return output;
|
|
2393
|
+
} else {
|
|
2394
|
+
const result = {
|
|
2395
|
+
noFeedbackAvailable: true,
|
|
2396
|
+
success: true,
|
|
2397
|
+
reason: (feedbackAccess == null ? void 0 : feedbackAccess.reason) || "No feedback access",
|
|
2398
|
+
accessType: (feedbackAccess == null ? void 0 : feedbackAccess.accessType) || "none"
|
|
2399
|
+
};
|
|
2400
|
+
onCompletionSuccess(result);
|
|
2401
|
+
return result;
|
|
2402
|
+
}
|
|
2403
|
+
} catch (error) {
|
|
2404
|
+
console.error("Error getting feedback:", error);
|
|
2405
|
+
throw new Error(error);
|
|
2406
|
+
}
|
|
2407
|
+
};
|
|
2408
|
+
const getAIResponse = async ({ cardId, transcript }) => {
|
|
2409
|
+
var _a, _b, _c, _d, _e;
|
|
2410
|
+
try {
|
|
2411
|
+
const getGeminiFeedback = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "callGetFeedback");
|
|
2412
|
+
const getProficiencyEstimate = (_d = (_c = api).httpsCallable) == null ? void 0 : _d.call(_c, "getProficiencyEstimate");
|
|
2413
|
+
const card = getCardFromCache({
|
|
2414
|
+
cardId,
|
|
2415
|
+
queryClient
|
|
2416
|
+
});
|
|
2417
|
+
let feedbackData;
|
|
2418
|
+
let proficiencyData = {};
|
|
2419
|
+
if (card && card.grading_method === "manual") {
|
|
2420
|
+
} else if (card && card.grading_method !== "standards_based") {
|
|
2421
|
+
const [geminiResult, proficiencyResult] = await Promise.all([
|
|
2422
|
+
getGeminiFeedback == null ? void 0 : getGeminiFeedback({
|
|
2423
|
+
cardId,
|
|
2424
|
+
studentId: currentUserId,
|
|
2425
|
+
studentResponse: transcript
|
|
2426
|
+
}),
|
|
2427
|
+
getProficiencyEstimate == null ? void 0 : getProficiencyEstimate({
|
|
2428
|
+
cardId,
|
|
2429
|
+
studentId: currentUserId,
|
|
2430
|
+
studentResponse: transcript
|
|
2431
|
+
})
|
|
2432
|
+
]);
|
|
2433
|
+
proficiencyData = (proficiencyResult == null ? void 0 : proficiencyResult.data) || {};
|
|
2434
|
+
feedbackData = {
|
|
2435
|
+
...(_e = geminiResult == null ? void 0 : geminiResult.data) != null ? _e : {},
|
|
2436
|
+
// @ts-ignore
|
|
2437
|
+
proficiency_level: (proficiencyData == null ? void 0 : proficiencyData.proficiency_level) || null
|
|
2438
|
+
};
|
|
2439
|
+
} else {
|
|
2440
|
+
const geminiResult = await (getGeminiFeedback == null ? void 0 : getGeminiFeedback({
|
|
2441
|
+
cardId,
|
|
2442
|
+
studentId: currentUserId,
|
|
2443
|
+
studentResponse: transcript
|
|
2444
|
+
}));
|
|
2445
|
+
feedbackData = geminiResult == null ? void 0 : geminiResult.data;
|
|
2446
|
+
}
|
|
2447
|
+
const results = {
|
|
2448
|
+
...feedbackData,
|
|
2449
|
+
// ...proficiencyData,
|
|
2450
|
+
aiSuccess: true,
|
|
2451
|
+
promptSuccess: (feedbackData == null ? void 0 : feedbackData.success) || false,
|
|
2452
|
+
transcript
|
|
2453
|
+
};
|
|
2454
|
+
return results;
|
|
2455
|
+
} catch (error) {
|
|
2456
|
+
onCompletionError({
|
|
2457
|
+
type: "AI_FEEDBACK",
|
|
2458
|
+
message: (error == null ? void 0 : error.message) || "Error getting ai feedback"
|
|
2459
|
+
});
|
|
2460
|
+
throw new Error(error);
|
|
2461
|
+
}
|
|
2462
|
+
};
|
|
2463
|
+
return {
|
|
2464
|
+
submitAudioResponse,
|
|
2465
|
+
uploadAudioAndGetTranscript,
|
|
2466
|
+
getTranscript,
|
|
2467
|
+
getFreeResponseCompletion,
|
|
2468
|
+
getFeedback
|
|
2469
|
+
};
|
|
2470
|
+
};
|
|
2471
|
+
|
|
2472
|
+
// src/hooks/useUserPlan.ts
|
|
2473
|
+
function useUserPlan() {
|
|
2474
|
+
const { permissions } = useSpeakableApi();
|
|
2475
|
+
const checkIsTeacherProPlan = (plan) => plan === SpeakablePlanTypes.teacher_pro || plan === SpeakablePlanTypes.starter;
|
|
2476
|
+
const checkIsOrganizationPlan = (plan) => plan === SpeakablePlanTypes.organization || plan === SpeakablePlanTypes.professional || plan === SpeakablePlanTypes.growth;
|
|
2477
|
+
const checkIsSchoolStarter = (plan) => plan === SpeakablePlanTypes.school_starter;
|
|
2478
|
+
const checkIsFreePlan = (plan) => plan === SpeakablePlanTypes.basic || !plan;
|
|
2479
|
+
return {
|
|
2480
|
+
userPlan: permissions.plan,
|
|
2481
|
+
loaded: !!permissions.plan,
|
|
2482
|
+
isFreePlan: checkIsFreePlan(permissions.plan),
|
|
2483
|
+
isTeacherProPlan: checkIsTeacherProPlan(permissions.plan),
|
|
2484
|
+
isOrganizationPlan: checkIsOrganizationPlan(permissions.plan),
|
|
2485
|
+
isSchoolStarter: checkIsSchoolStarter(permissions.plan),
|
|
2486
|
+
checkIsFreePlan,
|
|
2487
|
+
checkIsTeacherProPlan,
|
|
2488
|
+
checkIsOrganizationPlan
|
|
2489
|
+
};
|
|
1547
2490
|
}
|
|
2491
|
+
|
|
2492
|
+
// src/hooks/useOrganizationAccess.ts
|
|
2493
|
+
import { useQuery as useQuery6 } from "@tanstack/react-query";
|
|
2494
|
+
var useOrganizationAccess = () => {
|
|
2495
|
+
const { user } = useSpeakableApi();
|
|
2496
|
+
const email = user.auth.email;
|
|
2497
|
+
const query = useQuery6({
|
|
2498
|
+
queryKey: ["organizationAccess", email],
|
|
2499
|
+
queryFn: async () => {
|
|
2500
|
+
if (!email) {
|
|
2501
|
+
return {
|
|
2502
|
+
hasUnlimitedAccess: false,
|
|
2503
|
+
subscriptionId: null,
|
|
2504
|
+
organizationId: null,
|
|
2505
|
+
organizationName: null,
|
|
2506
|
+
subscriptionEndDate: null,
|
|
2507
|
+
accessType: "individual"
|
|
2508
|
+
};
|
|
2509
|
+
}
|
|
2510
|
+
return getOrganizationAccess(email);
|
|
2511
|
+
},
|
|
2512
|
+
enabled: !!email,
|
|
2513
|
+
// Only run query if we have a user email
|
|
2514
|
+
staleTime: 5 * 60 * 1e3,
|
|
2515
|
+
// Consider data fresh for 5 minutes
|
|
2516
|
+
gcTime: 10 * 60 * 1e3,
|
|
2517
|
+
// Keep in cache for 10 minutes
|
|
2518
|
+
retry: 2
|
|
2519
|
+
// Retry failed requests twice
|
|
2520
|
+
});
|
|
2521
|
+
return {
|
|
2522
|
+
...query
|
|
2523
|
+
};
|
|
2524
|
+
};
|
|
2525
|
+
var getOrganizationAccess = async (email) => {
|
|
2526
|
+
const { limit, where } = api.accessQueryConstraints();
|
|
2527
|
+
try {
|
|
2528
|
+
const organizationSnapshot = await api.getDocs(
|
|
2529
|
+
"organizations",
|
|
2530
|
+
where("members", "array-contains", email),
|
|
2531
|
+
where("masterSubscriptionStatus", "==", "active"),
|
|
2532
|
+
limit(1)
|
|
2533
|
+
);
|
|
2534
|
+
if (!organizationSnapshot.empty) {
|
|
2535
|
+
const orgData = organizationSnapshot.data[0];
|
|
2536
|
+
return {
|
|
2537
|
+
hasUnlimitedAccess: true,
|
|
2538
|
+
subscriptionId: orgData == null ? void 0 : orgData.masterSubscriptionId,
|
|
2539
|
+
organizationId: orgData.id,
|
|
2540
|
+
organizationName: orgData.name || "Unknown Organization",
|
|
2541
|
+
subscriptionEndDate: orgData.masterSubscriptionEndDate || null,
|
|
2542
|
+
accessType: "organization"
|
|
2543
|
+
};
|
|
2544
|
+
}
|
|
2545
|
+
const institutionSnapshot = await api.getDocs(
|
|
2546
|
+
"institution_subscriptions",
|
|
2547
|
+
where("users", "array-contains", email),
|
|
2548
|
+
where("active", "==", true),
|
|
2549
|
+
limit(1)
|
|
2550
|
+
);
|
|
2551
|
+
if (!institutionSnapshot.empty) {
|
|
2552
|
+
const institutionData = institutionSnapshot.data[0];
|
|
2553
|
+
const isUnlimited = (institutionData == null ? void 0 : institutionData.plan) === "organization" || (institutionData == null ? void 0 : institutionData.plan) === "school_starter";
|
|
2554
|
+
return {
|
|
2555
|
+
hasUnlimitedAccess: isUnlimited,
|
|
2556
|
+
subscriptionId: institutionData.id,
|
|
2557
|
+
organizationId: institutionData == null ? void 0 : institutionData.institutionId,
|
|
2558
|
+
organizationName: institutionData.name || institutionData.institutionId || "Legacy Institution",
|
|
2559
|
+
subscriptionEndDate: institutionData.endDate || null,
|
|
2560
|
+
accessType: "institution_subscriptions"
|
|
2561
|
+
};
|
|
2562
|
+
}
|
|
2563
|
+
return {
|
|
2564
|
+
hasUnlimitedAccess: false,
|
|
2565
|
+
subscriptionId: null,
|
|
2566
|
+
organizationId: null,
|
|
2567
|
+
organizationName: null,
|
|
2568
|
+
subscriptionEndDate: null,
|
|
2569
|
+
accessType: "individual"
|
|
2570
|
+
};
|
|
2571
|
+
} catch (error) {
|
|
2572
|
+
console.error("Error checking organization access:", error);
|
|
2573
|
+
return {
|
|
2574
|
+
hasUnlimitedAccess: false,
|
|
2575
|
+
subscriptionId: null,
|
|
2576
|
+
organizationId: null,
|
|
2577
|
+
organizationName: null,
|
|
2578
|
+
subscriptionEndDate: null,
|
|
2579
|
+
accessType: "individual"
|
|
2580
|
+
};
|
|
2581
|
+
}
|
|
2582
|
+
};
|
|
2583
|
+
|
|
2584
|
+
// src/hooks/useUpdateStudentVoc.ts
|
|
2585
|
+
var useUpdateStudentVocab = (page) => {
|
|
2586
|
+
const { user } = useSpeakableApi();
|
|
2587
|
+
const currentUserId = user == null ? void 0 : user.auth.uid;
|
|
2588
|
+
if (!page || !currentUserId || !page.target_text || !page.language) {
|
|
2589
|
+
return {
|
|
2590
|
+
studentVocabMarkVoiceSuccess: void 0,
|
|
2591
|
+
studentVocabMarkVoiceFail: void 0
|
|
2592
|
+
};
|
|
2593
|
+
}
|
|
2594
|
+
const getDataObject = () => {
|
|
2595
|
+
var _a, _b;
|
|
2596
|
+
const { serverTimestamp } = api.accessHelpers();
|
|
2597
|
+
const language = (_a = page.language) != null ? _a : "en";
|
|
2598
|
+
const word = (_b = page.target_text) != null ? _b : "";
|
|
2599
|
+
const phrase_length = getPhraseLength(word);
|
|
2600
|
+
const wordHash = getWordHash(word, language);
|
|
2601
|
+
const docPath = `users/${currentUserId}/vocab/${wordHash}`;
|
|
2602
|
+
const communityPath = `checked-pronunciations/${wordHash}`;
|
|
2603
|
+
const id = `${language}-${cleanString(word)}`;
|
|
2604
|
+
const data = {
|
|
2605
|
+
id,
|
|
2606
|
+
word,
|
|
2607
|
+
words: (word == null ? void 0 : word.split(" ")) || [],
|
|
2608
|
+
wordHash,
|
|
2609
|
+
language,
|
|
2610
|
+
lastSeen: serverTimestamp(),
|
|
2611
|
+
phrase_length
|
|
2612
|
+
};
|
|
2613
|
+
return {
|
|
2614
|
+
docPath,
|
|
2615
|
+
communityPath,
|
|
2616
|
+
data
|
|
2617
|
+
};
|
|
2618
|
+
};
|
|
2619
|
+
const markVoiceSuccess = async () => {
|
|
2620
|
+
const { docPath, communityPath, data } = getDataObject();
|
|
2621
|
+
const { increment } = api.accessQueryConstraints();
|
|
2622
|
+
const { serverTimestamp } = api.accessHelpers();
|
|
2623
|
+
data.voiceSuccess = increment(1);
|
|
2624
|
+
try {
|
|
2625
|
+
await api.updateDoc(docPath, data);
|
|
2626
|
+
} catch (error) {
|
|
2627
|
+
if (error instanceof Error && error.message === "not-found") {
|
|
2628
|
+
data.firstSeen = serverTimestamp();
|
|
2629
|
+
await api.setDoc(docPath, data, { merge: true });
|
|
2630
|
+
} else {
|
|
2631
|
+
console.log(error);
|
|
2632
|
+
}
|
|
2633
|
+
}
|
|
2634
|
+
try {
|
|
2635
|
+
data.pronunciations = increment(1);
|
|
2636
|
+
await api.setDoc(communityPath, data, { merge: true });
|
|
2637
|
+
} catch (error) {
|
|
2638
|
+
console.log(error);
|
|
2639
|
+
}
|
|
2640
|
+
};
|
|
2641
|
+
const markVoiceFail = async () => {
|
|
2642
|
+
const { docPath, communityPath, data } = getDataObject();
|
|
2643
|
+
const { increment } = api.accessQueryConstraints();
|
|
2644
|
+
const { serverTimestamp } = api.accessHelpers();
|
|
2645
|
+
data.voiceFail = increment(1);
|
|
2646
|
+
try {
|
|
2647
|
+
await api.updateDoc(docPath, data);
|
|
2648
|
+
} catch (error) {
|
|
2649
|
+
if (error instanceof Error && error.message === "not-found") {
|
|
2650
|
+
data.firstSeen = serverTimestamp();
|
|
2651
|
+
await api.setDoc(docPath, data, { merge: true });
|
|
2652
|
+
} else {
|
|
2653
|
+
console.log(error);
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
try {
|
|
2657
|
+
data.fails = increment(1);
|
|
2658
|
+
await api.setDoc(communityPath, data, { merge: true });
|
|
2659
|
+
} catch (error) {
|
|
2660
|
+
console.log(error);
|
|
2661
|
+
}
|
|
2662
|
+
};
|
|
2663
|
+
return {
|
|
2664
|
+
studentVocabMarkVoiceSuccess: markVoiceSuccess,
|
|
2665
|
+
studentVocabMarkVoiceFail: markVoiceFail
|
|
2666
|
+
};
|
|
2667
|
+
};
|
|
1548
2668
|
export {
|
|
2669
|
+
activityFeedbackAccessQueryKeys,
|
|
1549
2670
|
assignmentQueryKeys,
|
|
1550
2671
|
cardsQueryKeys,
|
|
1551
2672
|
getCardFromCache,
|
|
@@ -1554,18 +2675,25 @@ export {
|
|
|
1554
2675
|
setsQueryKeys,
|
|
1555
2676
|
updateCardInCache,
|
|
1556
2677
|
updateSetInCache,
|
|
2678
|
+
useActivity,
|
|
2679
|
+
useActivityFeedbackAccess,
|
|
1557
2680
|
useAssignment,
|
|
2681
|
+
useBaseOpenAI,
|
|
1558
2682
|
useCards,
|
|
1559
2683
|
useClearScore,
|
|
1560
2684
|
useCreateCard,
|
|
1561
2685
|
useCreateCards,
|
|
1562
2686
|
useCreateNotification,
|
|
1563
2687
|
useGetCard,
|
|
2688
|
+
useGoogleClassroom,
|
|
2689
|
+
useOrganizationAccess,
|
|
1564
2690
|
useScore,
|
|
1565
2691
|
useSet,
|
|
1566
2692
|
useSubmitAssignmentScore,
|
|
1567
2693
|
useSubmitPracticeScore,
|
|
1568
2694
|
useUpdateCardScore,
|
|
1569
|
-
useUpdateScore
|
|
2695
|
+
useUpdateScore,
|
|
2696
|
+
useUpdateStudentVocab,
|
|
2697
|
+
useUserPlan
|
|
1570
2698
|
};
|
|
1571
2699
|
//# sourceMappingURL=hooks.js.map
|