@speakableio/core 0.1.58 → 0.1.59

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.
@@ -363,451 +363,280 @@ function useAssignment({
363
363
  });
364
364
  }
365
365
 
366
- // src/domains/cards/card.hooks.ts
367
- import { useMutation, useQueries, useQuery as useQuery2 } from "@tanstack/react-query";
368
- import { useMemo } from "react";
369
-
370
- // src/domains/cards/card.constants.ts
371
- var FeedbackTypesCard = /* @__PURE__ */ ((FeedbackTypesCard2) => {
372
- FeedbackTypesCard2["SuggestedResponse"] = "suggested_response";
373
- FeedbackTypesCard2["Wida"] = "wida";
374
- FeedbackTypesCard2["GrammarInsights"] = "grammar_insights";
375
- FeedbackTypesCard2["Actfl"] = "actfl";
376
- FeedbackTypesCard2["ProficiencyLevel"] = "proficiency_level";
377
- return FeedbackTypesCard2;
378
- })(FeedbackTypesCard || {});
379
- var LeniencyCard = /* @__PURE__ */ ((LeniencyCard2) => {
380
- LeniencyCard2["CONFIDENCE"] = "confidence";
381
- LeniencyCard2["EASY"] = "easy";
382
- LeniencyCard2["NORMAL"] = "normal";
383
- LeniencyCard2["HARD"] = "hard";
384
- return LeniencyCard2;
385
- })(LeniencyCard || {});
386
- var LENIENCY_OPTIONS = [
387
- {
388
- label: "Build Confidence - most lenient",
389
- value: "confidence" /* CONFIDENCE */
390
- },
391
- {
392
- label: "Very Lenient",
393
- value: "easy" /* EASY */
394
- },
395
- {
396
- label: "Normal",
397
- value: "normal" /* NORMAL */
398
- },
399
- {
400
- label: "No leniency - most strict",
401
- value: "hard" /* HARD */
402
- }
403
- ];
404
- var STUDENT_LEVELS_OPTIONS = [
405
- {
406
- label: "Beginner",
407
- description: "Beginner Level: Just starting out. Can say a few basic words and phrases.",
408
- value: "beginner"
409
- },
410
- {
411
- label: "Elementary",
412
- description: "Elementary Level: Can understand simple sentences and have very basic conversations.",
413
- value: "elementary"
414
- },
415
- {
416
- label: "Intermediate",
417
- description: "Intermediate Level: Can talk about everyday topics and handle common situations.",
418
- value: "intermediate"
419
- },
420
- {
421
- label: "Advanced",
422
- description: "Advanced Level: Can speak and understand with ease, and explain ideas clearly.",
423
- value: "advanced"
424
- },
425
- {
426
- label: "Fluent",
427
- description: "Fluent Level: Speaks naturally and easily. Can use the language in work or school settings.",
428
- value: "fluent"
429
- },
430
- {
431
- label: "Native-like",
432
- description: "Native-like Level: Understands and speaks like a native. Can discuss complex ideas accurately.",
433
- value: "nativeLike"
434
- }
435
- ];
436
- var BASE_RESPOND_FIELD_VALUES = {
437
- title: "",
438
- allowRetries: true,
439
- respondTime: 180,
440
- maxCharacters: 1e3
441
- };
442
- var BASE_REPEAT_FIELD_VALUES = {
443
- repeat: 1
444
- };
445
- var BASE_MULTIPLE_CHOICE_FIELD_VALUES = {
446
- MCQType: "single",
447
- answer: ["A"],
448
- choices: [
449
- { option: "A", value: "Option A" },
450
- { option: "B", value: "Option B" },
451
- { option: "C", value: "Option C" }
452
- ]
453
- };
454
- var VerificationCardStatus = /* @__PURE__ */ ((VerificationCardStatus2) => {
455
- VerificationCardStatus2["VERIFIED"] = "VERIFIED";
456
- VerificationCardStatus2["WARNING"] = "WARNING";
457
- VerificationCardStatus2["NOT_RECOMMENDED"] = "NOT_RECOMMENDED";
458
- VerificationCardStatus2["NOT_WORKING"] = "NOT_WORKING";
459
- VerificationCardStatus2["NOT_CHECKED"] = "NOT_CHECKED";
460
- return VerificationCardStatus2;
461
- })(VerificationCardStatus || {});
462
- var CARDS_COLLECTION = "flashcards";
463
- var refsCardsFiresotre = {
464
- allCards: CARDS_COLLECTION,
465
- card: (id) => `${CARDS_COLLECTION}/${id}`
466
- };
366
+ // src/domains/assignment/hooks/score-hooks.ts
367
+ import { useMutation, useQuery as useQuery2 } from "@tanstack/react-query";
467
368
 
468
- // src/domains/cards/services/get-card.service.ts
469
- async function _getCard(params) {
470
- const ref = refsCardsFiresotre.card(params.cardId);
471
- const response = await api.getDoc(ref);
472
- if (!response.data) return null;
473
- return response.data;
369
+ // src/utils/debounce.utils.ts
370
+ function debounce(func, waitFor) {
371
+ let timeoutId;
372
+ return (...args) => new Promise((resolve, reject) => {
373
+ if (timeoutId) {
374
+ clearTimeout(timeoutId);
375
+ }
376
+ timeoutId = setTimeout(async () => {
377
+ try {
378
+ const result = await func(...args);
379
+ resolve(result);
380
+ } catch (error) {
381
+ reject(error);
382
+ }
383
+ }, waitFor);
384
+ });
474
385
  }
475
- var getCard = withErrorHandler(_getCard, "getCard");
476
-
477
- // src/domains/cards/services/create-card.service.ts
478
- import { v4 } from "uuid";
479
-
480
- // src/domains/cards/card.model.ts
481
- var CardActivityType = /* @__PURE__ */ ((CardActivityType2) => {
482
- CardActivityType2["READ_REPEAT"] = "READ_REPEAT";
483
- CardActivityType2["VIDEO"] = "VIDEO";
484
- CardActivityType2["TEXT"] = "TEXT";
485
- CardActivityType2["READ_RESPOND"] = "READ_RESPOND";
486
- CardActivityType2["FREE_RESPONSE"] = "FREE_RESPONSE";
487
- CardActivityType2["REPEAT"] = "REPEAT";
488
- CardActivityType2["RESPOND"] = "RESPOND";
489
- CardActivityType2["RESPOND_WRITE"] = "RESPOND_WRITE";
490
- CardActivityType2["TEXT_TO_SPEECH"] = "TEXT_TO_SPEECH";
491
- CardActivityType2["MULTIPLE_CHOICE"] = "MULTIPLE_CHOICE";
492
- CardActivityType2["PODCAST"] = "PODCAST";
493
- CardActivityType2["MEDIA_PAGE"] = "MEDIA_PAGE";
494
- CardActivityType2["WRITE"] = "WRITE";
495
- CardActivityType2["SHORT_ANSWER"] = "SHORT_ANSWER";
496
- CardActivityType2["SHORT_STORY"] = "SHORT_STORY";
497
- CardActivityType2["SPEAK"] = "SPEAK";
498
- CardActivityType2["CONVERSATION"] = "CONVERSATION";
499
- CardActivityType2["CONVERSATION_WRITE"] = "CONVERSATION_WRITE";
500
- CardActivityType2["DIALOGUE"] = "DIALOGUE";
501
- CardActivityType2["INSTRUCTION"] = "INSTRUCTION";
502
- CardActivityType2["LISTEN"] = "LISTEN";
503
- CardActivityType2["READ"] = "READ";
504
- CardActivityType2["ANSWER"] = "ANSWER";
505
- return CardActivityType2;
506
- })(CardActivityType || {});
507
- var RESPOND_CARD_ACTIVITY_TYPES = [
508
- "READ_RESPOND" /* READ_RESPOND */,
509
- "RESPOND" /* RESPOND */,
510
- "RESPOND_WRITE" /* RESPOND_WRITE */,
511
- "FREE_RESPONSE" /* FREE_RESPONSE */
512
- ];
513
- var MULTIPLE_CHOICE_CARD_ACTIVITY_TYPES = ["MULTIPLE_CHOICE" /* MULTIPLE_CHOICE */];
514
- var REPEAT_CARD_ACTIVITY_TYPES = ["READ_REPEAT" /* READ_REPEAT */, "REPEAT" /* REPEAT */];
515
- var RESPOND_WRITE_CARD_ACTIVITY_TYPES = [
516
- "RESPOND_WRITE" /* RESPOND_WRITE */,
517
- "FREE_RESPONSE" /* FREE_RESPONSE */
518
- ];
519
- var RESPOND_AUDIO_CARD_ACTIVITY_TYPES = [
520
- "RESPOND" /* RESPOND */,
521
- "READ_RESPOND" /* READ_RESPOND */
522
- ];
523
- var ALLOWED_CARD_ACTIVITY_TYPES_FOR_SUMMARY = [
524
- "REPEAT" /* REPEAT */,
525
- "RESPOND" /* RESPOND */,
526
- "READ_REPEAT" /* READ_REPEAT */,
527
- "READ_RESPOND" /* READ_RESPOND */,
528
- "FREE_RESPONSE" /* FREE_RESPONSE */,
529
- "RESPOND_WRITE" /* RESPOND_WRITE */,
530
- "MULTIPLE_CHOICE" /* MULTIPLE_CHOICE */
531
- ];
532
386
 
533
- // src/utils/text-utils.ts
534
- import sha1 from "js-sha1";
535
- var purify = (word) => {
536
- 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();
537
- };
538
- var cleanString = (words) => {
539
- const splitWords = words == null ? void 0 : words.split("+");
540
- if (splitWords && splitWords.length === 1) {
541
- const newWord = purify(words);
542
- return newWord;
543
- } else if (splitWords && splitWords.length > 1) {
544
- const split = splitWords.map((w) => purify(w));
545
- return split;
387
+ // src/lib/tanstack/handle-optimistic-update-query.ts
388
+ var handleOptimisticUpdate = async ({
389
+ queryClient,
390
+ queryKey,
391
+ newData
392
+ }) => {
393
+ await queryClient.cancelQueries({
394
+ queryKey
395
+ });
396
+ const previousData = queryClient.getQueryData(queryKey);
397
+ if (previousData === void 0) {
398
+ queryClient.setQueryData(queryKey, newData);
546
399
  } else {
547
- return "";
400
+ queryClient.setQueryData(queryKey, { ...previousData, ...newData });
548
401
  }
549
- };
550
- var getWordHash = (word, language) => {
551
- const cleanedWord = cleanString(word);
552
- const wordHash = sha1(`${language}-${cleanedWord}`);
553
- console.log("wordHash core library", wordHash);
554
- return wordHash;
402
+ return { previousData };
555
403
  };
556
404
 
557
- // src/domains/cards/services/get-card-verification-status.service.ts
558
- var charactarLanguages = ["zh", "ja", "ko"];
559
- var getVerificationStatus = async (target_text, language) => {
560
- if ((target_text == null ? void 0 : target_text.length) < 3 && !charactarLanguages.includes(language)) {
561
- return "NOT_RECOMMENDED" /* NOT_RECOMMENDED */;
562
- }
563
- const hash = getWordHash(target_text, language);
564
- const response = await api.getDoc(`checked-pronunciations/${hash}`);
565
- try {
566
- if (response.data) {
567
- return processRecord(response.data);
568
- } else {
569
- return "NOT_CHECKED" /* NOT_CHECKED */;
570
- }
571
- } catch (e) {
572
- return "NOT_CHECKED" /* NOT_CHECKED */;
573
- }
405
+ // src/constants/speakable-plans.ts
406
+ var FEEDBACK_PLANS = {
407
+ FEEDBACK_TRANSCRIPT: "FEEDBACK_TRANSCRIPT",
408
+ // Transcript from the audio
409
+ FEEDBACK_SUMMARY: "FEEDBACK_SUMMARY",
410
+ // Chatty summary (Free plan)
411
+ FEEDBACK_GRAMMAR_INSIGHTS: "FEEDBACK_GRAMMAR_INSIGHTS",
412
+ // Grammar insights
413
+ FEEDBACK_SUGGESTED_RESPONSE: "FEEDBACK_SUGGESTED_RESPONSE",
414
+ // Suggested Response
415
+ FEEDBACK_RUBRIC: "FEEDBACK_RUBRIC",
416
+ // Suggested Response
417
+ FEEDBACK_GRADING_STANDARDS: "FEEDBACK_GRADING_STANDARDS",
418
+ // ACTFL / WIDA Estimate
419
+ FEEDBACK_TARGET_LANGUAGE: "FEEDBACK_TARGET_LANGUAGE",
420
+ // Ability to set the feedback language to the target language of the student
421
+ FEEDBACK_DISABLE_ALLOW_RETRIES: "FEEDBACK_DISABLE_ALLOW_RETRIES"
422
+ // Turn of allow retries
574
423
  };
575
- var processRecord = (data) => {
576
- const { pronunciations = 0, fails = 0 } = data;
577
- const attempts = pronunciations + fails;
578
- const successRate = attempts > 0 ? pronunciations / attempts * 100 : 0;
579
- let newStatus = null;
580
- if (attempts < 6) {
581
- return "NOT_CHECKED" /* NOT_CHECKED */;
582
- }
583
- if (successRate > 25) {
584
- newStatus = "VERIFIED" /* VERIFIED */;
585
- } else if (successRate > 10) {
586
- newStatus = "WARNING" /* WARNING */;
587
- } else if (fails > 20 && successRate < 10 && pronunciations > 1) {
588
- newStatus = "NOT_RECOMMENDED" /* NOT_RECOMMENDED */;
589
- } else if (pronunciations === 0 && fails > 20) {
590
- newStatus = "NOT_WORKING" /* NOT_WORKING */;
591
- } else {
592
- newStatus = "NOT_CHECKED" /* NOT_CHECKED */;
593
- }
594
- return newStatus;
595
- };
596
-
597
- // src/domains/cards/services/create-card.service.ts
598
- async function _createCard({ data }) {
599
- const response = await api.addDoc(refsCardsFiresotre.allCards, data);
600
- return response;
601
- }
602
- var createCard = withErrorHandler(_createCard, "createCard");
603
- async function _createCards({ cards }) {
604
- const { writeBatch: writeBatch2, doc: doc2 } = api.accessHelpers();
605
- const batch = writeBatch2();
606
- const cardsWithId = [];
607
- for (const card of cards) {
608
- const cardId = v4();
609
- const ref = doc2(refsCardsFiresotre.card(cardId));
610
- const newCardObject = {
611
- ...card,
612
- id: cardId
613
- };
614
- if (card.type === "READ_REPEAT" /* READ_REPEAT */ && card.target_text && card.language) {
615
- const verificationStatus = await getVerificationStatus(card.target_text, card.language);
616
- newCardObject.verificationStatus = verificationStatus || null;
617
- }
618
- cardsWithId.push(newCardObject);
619
- batch.set(ref, newCardObject);
620
- }
621
- await batch.commit();
622
- return cardsWithId;
623
- }
624
- var createCards = withErrorHandler(_createCards, "createCards");
625
-
626
- // src/domains/cards/card.hooks.ts
627
- var cardsQueryKeys = {
628
- all: ["cards"],
629
- one: (params) => [...cardsQueryKeys.all, params.cardId]
630
- };
631
- function useCards({
632
- cardIds,
633
- enabled = true,
634
- asObject
635
- }) {
636
- const queries = useQueries({
637
- queries: cardIds.map((cardId) => ({
638
- enabled: enabled && cardIds.length > 0,
639
- queryKey: cardsQueryKeys.one({
640
- cardId
641
- }),
642
- queryFn: () => getCard({ cardId })
643
- }))
644
- });
645
- const cards = queries.map((query2) => query2.data).filter(Boolean);
646
- const cardsObject = useMemo(() => {
647
- if (!asObject) return null;
648
- return cards.reduce((acc, card) => {
649
- acc[card.id] = card;
650
- return acc;
651
- }, {});
652
- }, [asObject, cards]);
653
- return {
654
- cards,
655
- cardsObject,
656
- cardsQueries: queries
657
- };
658
- }
659
- function useCreateCard() {
660
- const { queryClient } = useSpeakableApi();
661
- const mutationCreateCard = useMutation({
662
- mutationFn: createCard,
663
- onSuccess: (cardCreated) => {
664
- queryClient.invalidateQueries({ queryKey: cardsQueryKeys.one({ cardId: cardCreated.id }) });
665
- }
666
- });
667
- return {
668
- mutationCreateCard
669
- };
670
- }
671
- function useCreateCards() {
672
- const mutationCreateCards = useMutation({
673
- mutationFn: createCards
674
- });
675
- return {
676
- mutationCreateCards
677
- };
678
- }
679
- function getCardFromCache({
680
- cardId,
681
- queryClient
682
- }) {
683
- return queryClient.getQueryData(cardsQueryKeys.one({ cardId }));
684
- }
685
- function updateCardInCache({
686
- cardId,
687
- card,
688
- queryClient
689
- }) {
690
- queryClient.setQueryData(cardsQueryKeys.one({ cardId }), card);
691
- }
692
- function useGetCard({ cardId }) {
693
- const query2 = useQuery2({
694
- queryKey: cardsQueryKeys.one({ cardId }),
695
- queryFn: () => getCard({ cardId })
696
- });
697
- return query2;
698
- }
699
-
700
- // src/domains/cards/card.repo.ts
701
- var createCardRepo = () => {
702
- return {
703
- createCard,
704
- createCards,
705
- getCard
706
- };
707
- };
708
-
709
- // src/domains/sets/set.hooks.ts
710
- import { useQuery as useQuery3 } from "@tanstack/react-query";
711
-
712
- // src/domains/sets/set.constants.ts
713
- var SETS_COLLECTION = "sets";
714
- var refsSetsFirestore = {
715
- allSets: SETS_COLLECTION,
716
- set: (id) => `${SETS_COLLECTION}/${id}`
424
+ var AUTO_GRADING_PLANS = {
425
+ AUTO_GRADING_PASS_FAIL: "AUTO_GRADING_PASS_FAIL",
426
+ // Pass / fail grading
427
+ AUTO_GRADING_RUBRICS: "AUTO_GRADING_RUBRICS",
428
+ // Autograded rubrics
429
+ AUTO_GRADING_STANDARDS_BASED: "AUTO_GRADING_STANDARDS_BASED"
430
+ // Standards based grading
717
431
  };
718
-
719
- // src/domains/sets/services/get-set.service.ts
720
- async function _getSet({ setId }) {
721
- const response = await api.getDoc(refsSetsFirestore.set(setId));
722
- return response.data;
723
- }
724
- var getSet = withErrorHandler(_getSet, "getSet");
725
-
726
- // src/domains/sets/set.hooks.ts
727
- var setsQueryKeys = {
728
- all: ["sets"],
729
- one: (params) => [...setsQueryKeys.all, params.setId]
432
+ var AI_ASSISTANT_PLANS = {
433
+ AI_ASSISTANT_DOCUMENT_UPLOADS: "AI_ASSISTANT_DOCUMENT_UPLOADS",
434
+ // Allow document uploading
435
+ AI_ASSISTANT_UNLIMITED_USE: "AI_ASSISTANT_UNLIMITED_USE"
436
+ // Allow unlimited use of AI assistant. Otherwise, limits are used.
730
437
  };
731
- var useSet = ({ setId, enabled }) => {
732
- return useQuery3({
733
- queryKey: setsQueryKeys.one({ setId }),
734
- queryFn: () => getSet({ setId }),
735
- enabled: setId !== void 0 && setId !== "" && enabled
736
- });
438
+ var ASSIGNMENT_SETTINGS_PLANS = {
439
+ ASSESSMENTS: "ASSESSMENTS",
440
+ // Ability to create assessment assignment types
441
+ GOOGLE_CLASSROOM_GRADE_PASSBACK: "GOOGLE_CLASSROOM_GRADE_PASSBACK"
442
+ // Assignment scores can sync with classroom
737
443
  };
738
- function getSetFromCache({
739
- setId,
740
- queryClient
741
- }) {
742
- if (!setId) return null;
743
- return queryClient.getQueryData(setsQueryKeys.one({ setId }));
744
- }
745
- function updateSetInCache({
746
- set,
747
- queryClient
748
- }) {
749
- const { id, ...setData } = set;
750
- queryClient.setQueryData(setsQueryKeys.one({ setId: id }), setData);
751
- }
752
-
753
- // src/domains/sets/set.repo.ts
754
- var createSetRepo = () => {
755
- return {
756
- getSet
757
- };
444
+ var ANALYTICS_PLANS = {
445
+ ANALYTICS_GRADEBOOK: "ANALYTICS_GRADEBOOK",
446
+ // Access to the gradebook page
447
+ ANALYTICS_CLASSROOM_ANALYTICS: "ANALYTICS_CLASSROOM_ANALYTICS",
448
+ // Access to the classroom analytics page
449
+ ANALYTICS_STUDENT_PROGRESS_REPORTS: "ANALYTICS_STUDENT_PROGRESS_REPORTS",
450
+ // Access to the panel that shows an individual student's progress and assignments
451
+ ANALYTICS_ASSIGNMENT_RESULTS: "ANALYTICS_ASSIGNMENT_RESULTS",
452
+ // Access to the assigment RESULTS page
453
+ ANALYTICS_ORGANIZATION: "ANALYTICS_ORGANIZATION"
454
+ // Access to the organization analytics panel (for permitted admins)
758
455
  };
759
-
760
- // src/domains/notification/notification.constants.ts
761
- var SPEAKABLE_NOTIFICATIONS = {
762
- NEW_ASSIGNMENT: "new_assignment",
763
- ASSESSMENT_SUBMITTED: "assessment_submitted",
764
- ASSESSMENT_SCORED: "assessment_scored",
765
- NEW_COMMENT: "NEW_COMMENT"
456
+ var SPACES_PLANS = {
457
+ SPACES_CREATE_SPACE: "SPACES_CREATE_SPACE",
458
+ // Ability to create spaces
459
+ SPACES_CHECK_POINTS: "SPACES_CHECK_POINTS"
460
+ // Feature not available yet. Ability to create checkpoints for spaces for data aggregation
766
461
  };
767
- var SpeakableNotificationTypes = {
768
- NEW_ASSIGNMENT: "NEW_ASSIGNMENT",
769
- FEEDBACK_FROM_TEACHER: "FEEDBACK_FROM_TEACHER",
770
- MESSAGE_FROM_STUDENT: "MESSAGE_FROM_STUDENT",
771
- PHRASE_MARKED_CORRECT: "PHRASE_MARKED_CORRECT",
772
- STUDENT_PROGRESS: "STUDENT_PROGRESS",
773
- PLAYLIST_FOLLOWERS: "PLAYLIST_FOLLOWERS",
774
- PLAYLIST_PLAYS: "PLAYLIST_PLAYS",
775
- // New notifications
776
- ASSESSMENT_SUBMITTED: "ASSESSMENT_SUBMITTED",
777
- // Notification FOR TEACHER when student submits assessment
778
- ASSESSMENT_SCORED: "ASSESSMENT_SCORED",
779
- // Notification FOR STUDENT when teacher scores assessment
780
- // Comment
781
- NEW_COMMENT: "NEW_COMMENT"
462
+ var DISCOVER_PLANS = {
463
+ DISCOVER_ORGANIZATION_LIBRARY: "DISCOVER_ORGANIZATION_LIBRARY"
464
+ // Access to the organizations shared library
782
465
  };
783
-
784
- // src/domains/notification/services/create-notification.service.ts
785
- import dayjs2 from "dayjs";
786
-
787
- // src/constants/web.constants.ts
788
- var WEB_BASE_URL = "https://app.speakable.io";
789
-
790
- // src/domains/notification/services/send-notification.service.ts
791
- var _sendNotification = async (sendTo, notification) => {
792
- var _a, _b, _c;
793
- const results = await ((_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "createNotificationV2")) == null ? void 0 : _c({
794
- sendTo,
795
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
796
- notification
797
- }));
798
- return results;
466
+ var MEDIA_AREA_PLANS = {
467
+ MEDIA_AREA_DOCUMENT_UPLOAD: "MEDIA_AREA_DOCUMENT_UPLOAD",
468
+ MEDIA_AREA_AUDIO_FILES: "MEDIA_AREA_AUDIO_FILES"
799
469
  };
800
- var sendNotification = withErrorHandler(_sendNotification, "sendNotification");
801
-
802
- // src/domains/notification/services/create-notification.service.ts
803
- var createNotification = async ({
804
- data,
805
- type,
806
- userId,
807
- profile
808
- }) => {
809
- let result;
810
- switch (type) {
470
+ var FREE_PLAN = [];
471
+ var TEACHER_PRO_PLAN = [
472
+ FEEDBACK_PLANS.FEEDBACK_TRANSCRIPT,
473
+ FEEDBACK_PLANS.FEEDBACK_SUMMARY,
474
+ FEEDBACK_PLANS.FEEDBACK_TARGET_LANGUAGE,
475
+ AUTO_GRADING_PLANS.AUTO_GRADING_PASS_FAIL,
476
+ ANALYTICS_PLANS.ANALYTICS_GRADEBOOK,
477
+ SPACES_PLANS.SPACES_CREATE_SPACE
478
+ // AUTO_GRADING_PLANS.AUTO_GRADING_STANDARDS_BASED,
479
+ ];
480
+ var SCHOOL_STARTER = [
481
+ FEEDBACK_PLANS.FEEDBACK_TRANSCRIPT,
482
+ FEEDBACK_PLANS.FEEDBACK_SUMMARY,
483
+ FEEDBACK_PLANS.FEEDBACK_GRAMMAR_INSIGHTS,
484
+ FEEDBACK_PLANS.FEEDBACK_SUGGESTED_RESPONSE,
485
+ FEEDBACK_PLANS.FEEDBACK_RUBRIC,
486
+ FEEDBACK_PLANS.FEEDBACK_GRADING_STANDARDS,
487
+ FEEDBACK_PLANS.FEEDBACK_DISABLE_ALLOW_RETRIES,
488
+ FEEDBACK_PLANS.FEEDBACK_TARGET_LANGUAGE,
489
+ AUTO_GRADING_PLANS.AUTO_GRADING_PASS_FAIL,
490
+ AUTO_GRADING_PLANS.AUTO_GRADING_RUBRICS,
491
+ AUTO_GRADING_PLANS.AUTO_GRADING_STANDARDS_BASED,
492
+ AI_ASSISTANT_PLANS.AI_ASSISTANT_DOCUMENT_UPLOADS,
493
+ AI_ASSISTANT_PLANS.AI_ASSISTANT_UNLIMITED_USE,
494
+ // ASSIGNMENT_SETTINGS_PLANS.ASSESSMENTS,
495
+ ASSIGNMENT_SETTINGS_PLANS.GOOGLE_CLASSROOM_GRADE_PASSBACK,
496
+ ANALYTICS_PLANS.ANALYTICS_GRADEBOOK,
497
+ ANALYTICS_PLANS.ANALYTICS_STUDENT_PROGRESS_REPORTS,
498
+ ANALYTICS_PLANS.ANALYTICS_CLASSROOM_ANALYTICS,
499
+ // ANALYTICS_PLANS.ANALYTICS_ORGANIZATION,
500
+ SPACES_PLANS.SPACES_CREATE_SPACE,
501
+ SPACES_PLANS.SPACES_CHECK_POINTS,
502
+ // DISCOVER_PLANS.DISCOVER_ORGANIZATION_LIBRARY,
503
+ MEDIA_AREA_PLANS.MEDIA_AREA_DOCUMENT_UPLOAD,
504
+ MEDIA_AREA_PLANS.MEDIA_AREA_AUDIO_FILES
505
+ ];
506
+ var ORGANIZATION_PLAN = [
507
+ FEEDBACK_PLANS.FEEDBACK_TRANSCRIPT,
508
+ FEEDBACK_PLANS.FEEDBACK_SUMMARY,
509
+ FEEDBACK_PLANS.FEEDBACK_GRAMMAR_INSIGHTS,
510
+ FEEDBACK_PLANS.FEEDBACK_SUGGESTED_RESPONSE,
511
+ FEEDBACK_PLANS.FEEDBACK_RUBRIC,
512
+ FEEDBACK_PLANS.FEEDBACK_GRADING_STANDARDS,
513
+ FEEDBACK_PLANS.FEEDBACK_DISABLE_ALLOW_RETRIES,
514
+ FEEDBACK_PLANS.FEEDBACK_TARGET_LANGUAGE,
515
+ AUTO_GRADING_PLANS.AUTO_GRADING_PASS_FAIL,
516
+ AUTO_GRADING_PLANS.AUTO_GRADING_RUBRICS,
517
+ AUTO_GRADING_PLANS.AUTO_GRADING_STANDARDS_BASED,
518
+ AI_ASSISTANT_PLANS.AI_ASSISTANT_DOCUMENT_UPLOADS,
519
+ AI_ASSISTANT_PLANS.AI_ASSISTANT_UNLIMITED_USE,
520
+ ASSIGNMENT_SETTINGS_PLANS.ASSESSMENTS,
521
+ ASSIGNMENT_SETTINGS_PLANS.GOOGLE_CLASSROOM_GRADE_PASSBACK,
522
+ ANALYTICS_PLANS.ANALYTICS_GRADEBOOK,
523
+ ANALYTICS_PLANS.ANALYTICS_STUDENT_PROGRESS_REPORTS,
524
+ ANALYTICS_PLANS.ANALYTICS_CLASSROOM_ANALYTICS,
525
+ ANALYTICS_PLANS.ANALYTICS_ORGANIZATION,
526
+ SPACES_PLANS.SPACES_CREATE_SPACE,
527
+ SPACES_PLANS.SPACES_CHECK_POINTS,
528
+ DISCOVER_PLANS.DISCOVER_ORGANIZATION_LIBRARY,
529
+ MEDIA_AREA_PLANS.MEDIA_AREA_DOCUMENT_UPLOAD,
530
+ MEDIA_AREA_PLANS.MEDIA_AREA_AUDIO_FILES
531
+ ];
532
+ var SpeakablePlanTypes = {
533
+ basic: "basic",
534
+ teacher_pro: "teacher_pro",
535
+ school_starter: "school_starter",
536
+ organization: "organization",
537
+ // OLD PLANS
538
+ starter: "starter",
539
+ growth: "growth",
540
+ professional: "professional"
541
+ };
542
+ var SpeakablePermissionsMap = {
543
+ [SpeakablePlanTypes.basic]: FREE_PLAN,
544
+ [SpeakablePlanTypes.starter]: TEACHER_PRO_PLAN,
545
+ [SpeakablePlanTypes.teacher_pro]: TEACHER_PRO_PLAN,
546
+ [SpeakablePlanTypes.growth]: ORGANIZATION_PLAN,
547
+ [SpeakablePlanTypes.professional]: ORGANIZATION_PLAN,
548
+ [SpeakablePlanTypes.organization]: ORGANIZATION_PLAN,
549
+ [SpeakablePlanTypes.school_starter]: SCHOOL_STARTER
550
+ };
551
+ var SpeakablePlanHierarchy = [
552
+ SpeakablePlanTypes.basic,
553
+ SpeakablePlanTypes.starter,
554
+ SpeakablePlanTypes.teacher_pro,
555
+ SpeakablePlanTypes.growth,
556
+ SpeakablePlanTypes.professional,
557
+ SpeakablePlanTypes.school_starter,
558
+ SpeakablePlanTypes.organization
559
+ ];
560
+
561
+ // src/hooks/usePermissions.ts
562
+ var usePermissions = () => {
563
+ const { permissions } = useSpeakableApi();
564
+ const has = (permission) => {
565
+ var _a;
566
+ return (_a = permissions.permissions) == null ? void 0 : _a.includes(permission);
567
+ };
568
+ return {
569
+ plan: permissions.plan,
570
+ permissionsLoaded: permissions.loaded,
571
+ isStripePlan: permissions.isStripePlan,
572
+ refreshDate: permissions.refreshDate,
573
+ isInstitutionPlan: permissions.isInstitutionPlan,
574
+ subscriptionId: permissions.subscriptionId,
575
+ contact: permissions.contact,
576
+ hasGradebook: has(ANALYTICS_PLANS.ANALYTICS_GRADEBOOK),
577
+ hasGoogleClassroomGradePassback: has(ASSIGNMENT_SETTINGS_PLANS.GOOGLE_CLASSROOM_GRADE_PASSBACK),
578
+ hasAssessments: has(ASSIGNMENT_SETTINGS_PLANS.ASSESSMENTS),
579
+ hasSectionAnalytics: has(ANALYTICS_PLANS.ANALYTICS_CLASSROOM_ANALYTICS),
580
+ hasStudentReports: has(ANALYTICS_PLANS.ANALYTICS_STUDENT_PROGRESS_REPORTS),
581
+ permissions: permissions || [],
582
+ hasStudentPortfolios: permissions.hasStudentPortfolios,
583
+ isFreeOrgTrial: permissions.type === "free_org_trial",
584
+ freeOrgTrialExpired: permissions.freeOrgTrialExpired
585
+ };
586
+ };
587
+ var usePermissions_default = usePermissions;
588
+
589
+ // src/domains/notification/notification.constants.ts
590
+ var SPEAKABLE_NOTIFICATIONS = {
591
+ NEW_ASSIGNMENT: "new_assignment",
592
+ ASSESSMENT_SUBMITTED: "assessment_submitted",
593
+ ASSESSMENT_SCORED: "assessment_scored",
594
+ NEW_COMMENT: "NEW_COMMENT"
595
+ };
596
+ var SpeakableNotificationTypes = {
597
+ NEW_ASSIGNMENT: "NEW_ASSIGNMENT",
598
+ FEEDBACK_FROM_TEACHER: "FEEDBACK_FROM_TEACHER",
599
+ MESSAGE_FROM_STUDENT: "MESSAGE_FROM_STUDENT",
600
+ PHRASE_MARKED_CORRECT: "PHRASE_MARKED_CORRECT",
601
+ STUDENT_PROGRESS: "STUDENT_PROGRESS",
602
+ PLAYLIST_FOLLOWERS: "PLAYLIST_FOLLOWERS",
603
+ PLAYLIST_PLAYS: "PLAYLIST_PLAYS",
604
+ // New notifications
605
+ ASSESSMENT_SUBMITTED: "ASSESSMENT_SUBMITTED",
606
+ // Notification FOR TEACHER when student submits assessment
607
+ ASSESSMENT_SCORED: "ASSESSMENT_SCORED",
608
+ // Notification FOR STUDENT when teacher scores assessment
609
+ // Comment
610
+ NEW_COMMENT: "NEW_COMMENT"
611
+ };
612
+
613
+ // src/domains/notification/services/create-notification.service.ts
614
+ import dayjs2 from "dayjs";
615
+
616
+ // src/constants/web.constants.ts
617
+ var WEB_BASE_URL = "https://app.speakable.io";
618
+
619
+ // src/domains/notification/services/send-notification.service.ts
620
+ var _sendNotification = async (sendTo, notification) => {
621
+ var _a, _b, _c;
622
+ const results = await ((_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "createNotificationV2")) == null ? void 0 : _c({
623
+ sendTo,
624
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
625
+ notification
626
+ }));
627
+ return results;
628
+ };
629
+ var sendNotification = withErrorHandler(_sendNotification, "sendNotification");
630
+
631
+ // src/domains/notification/services/create-notification.service.ts
632
+ var createNotification = async ({
633
+ data,
634
+ type,
635
+ userId,
636
+ profile
637
+ }) => {
638
+ let result;
639
+ switch (type) {
811
640
  case SPEAKABLE_NOTIFICATIONS.NEW_ASSIGNMENT:
812
641
  result = await handleAssignNotifPromise({ data, profile });
813
642
  break;
@@ -946,527 +775,53 @@ var useCreateNotification = () => {
946
775
  };
947
776
  };
948
777
 
949
- // src/constants/all-langs.json
950
- var all_langs_default = {
951
- af: "Afrikaans",
952
- sq: "Albanian",
953
- am: "Amharic",
954
- ar: "Arabic",
955
- hy: "Armenian",
956
- az: "Azerbaijani",
957
- eu: "Basque",
958
- be: "Belarusian",
959
- bn: "Bengali",
960
- bs: "Bosnian",
961
- bg: "Bulgarian",
962
- ca: "Catalan",
963
- ceb: "Cebuano",
964
- zh: "Chinese",
965
- co: "Corsican",
966
- hr: "Croatian",
967
- cs: "Czech",
968
- da: "Danish",
969
- nl: "Dutch",
970
- en: "English",
971
- eo: "Esperanto",
972
- et: "Estonian",
973
- fi: "Finnish",
974
- fr: "French",
975
- fy: "Frisian",
976
- gl: "Galician",
977
- ka: "Georgian",
978
- de: "German",
979
- el: "Greek",
980
- gu: "Gujarati",
981
- ht: "Haitian Creole",
982
- ha: "Hausa",
983
- haw: "Hawaiian",
984
- he: "Hebrew",
985
- hi: "Hindi",
986
- hmn: "Hmong",
987
- hu: "Hungarian",
988
- is: "Icelandic",
989
- ig: "Igbo",
990
- id: "Indonesian",
991
- ga: "Irish",
992
- it: "Italian",
993
- ja: "Japanese",
994
- jv: "Javanese",
995
- kn: "Kannada",
996
- kk: "Kazakh",
997
- km: "Khmer",
998
- ko: "Korean",
999
- ku: "Kurdish",
1000
- ky: "Kyrgyz",
1001
- lo: "Lao",
1002
- la: "Latin",
1003
- lv: "Latvian",
1004
- lt: "Lithuanian",
1005
- lb: "Luxembourgish",
1006
- mk: "Macedonian",
1007
- mg: "Malagasy",
1008
- ms: "Malay",
1009
- ml: "Malayalam",
1010
- mt: "Maltese",
1011
- mi: "Maori",
1012
- mr: "Marathi",
1013
- mn: "Mongolian",
1014
- my: "Myanmar (Burmese)",
1015
- ne: "Nepali",
1016
- no: "Norwegian",
1017
- ny: "Nyanja (Chichewa)",
1018
- ps: "Pashto",
1019
- fa: "Persian",
1020
- pl: "Polish",
1021
- pt: "Portuguese",
1022
- pa: "Punjabi",
1023
- ro: "Romanian",
1024
- ru: "Russian",
1025
- sm: "Samoan",
1026
- gd: "Scots Gaelic",
1027
- sr: "Serbian",
1028
- st: "Sesotho",
1029
- sn: "Shona",
1030
- sd: "Sindhi",
1031
- si: "Sinhala (Sinhalese)",
1032
- sk: "Slovak",
1033
- sl: "Slovenian",
1034
- so: "Somali",
1035
- es: "Spanish",
1036
- su: "Sundanese",
1037
- sw: "Swahili",
1038
- sv: "Swedish",
1039
- tl: "Tagalog (Filipino)",
1040
- tg: "Tajik",
1041
- ta: "Tamil",
1042
- te: "Telugu",
1043
- th: "Thai",
1044
- tr: "Turkish",
1045
- uk: "Ukrainian",
1046
- ur: "Urdu",
1047
- uz: "Uzbek",
1048
- vi: "Vietnamese",
1049
- cy: "Welsh",
1050
- xh: "Xhosa",
1051
- yi: "Yiddish",
1052
- yo: "Yoruba",
1053
- zu: "Zulu"
1054
- };
1055
-
1056
- // src/utils/ai/get-respond-card-tool.ts
1057
- var getRespondCardTool = ({
1058
- language,
1059
- standard = "actfl"
1060
- }) => {
1061
- const lang = all_langs_default[language] || "English";
1062
- const tool = {
1063
- tool_choice: {
1064
- type: "function",
1065
- function: { name: "get_feedback" }
1066
- },
1067
- tools: [
1068
- {
1069
- type: "function",
1070
- function: {
1071
- name: "get_feedback",
1072
- description: "Get feedback on a student's response",
1073
- parameters: {
1074
- type: "object",
1075
- required: [
1076
- "success",
1077
- "score",
1078
- "score_justification",
1079
- "errors",
1080
- "improvedResponse",
1081
- "compliments"
1082
- ],
1083
- properties: {
1084
- success: {
1085
- type: "boolean",
1086
- 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."
1087
- },
1088
- errors: {
1089
- type: "array",
1090
- items: {
1091
- type: "object",
1092
- required: ["error", "grammar_error_type", "correction", "justification"],
1093
- properties: {
1094
- error: {
1095
- type: "string",
1096
- description: "The grammatical error in the student's response."
1097
- },
1098
- correction: {
1099
- type: "string",
1100
- description: "The suggested correction to the error"
1101
- },
1102
- justification: {
1103
- type: "string",
1104
- description: `An explanation of the rationale behind the suggested correction. WRITE THIS IN ${lang}!`
1105
- },
1106
- grammar_error_type: {
1107
- type: "string",
1108
- enum: [
1109
- "subjVerbAgree",
1110
- "tenseErrors",
1111
- "articleMisuse",
1112
- "prepositionErrors",
1113
- "adjNounAgree",
1114
- "pronounErrors",
1115
- "wordOrder",
1116
- "verbConjugation",
1117
- "pluralization",
1118
- "negationErrors",
1119
- "modalVerbMisuse",
1120
- "relativeClause",
1121
- "auxiliaryVerb",
1122
- "complexSentenceAgreement",
1123
- "idiomaticExpression",
1124
- "registerInconsistency",
1125
- "voiceMisuse"
1126
- ],
1127
- 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"
1128
- }
1129
- }
1130
- },
1131
- 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."
1132
- },
1133
- compliments: {
1134
- type: "array",
1135
- items: {
1136
- type: "string"
1137
- },
1138
- description: `An array of strings, each representing something the student did well. Each string should be WRITTEN IN ${lang}!`
1139
- },
1140
- improvedResponse: {
1141
- type: "string",
1142
- description: "An improved response with proper grammar and more detail, if applicable."
1143
- },
1144
- score: {
1145
- type: "number",
1146
- description: "A score between 0 and 100, reflecting the overall quality of the response"
1147
- },
1148
- score_justification: {
1149
- type: "string",
1150
- description: "An explanation of the rationale behind the assigned score, considering both accuracy and fluency"
1151
- }
1152
- }
1153
- }
1154
- }
1155
- }
1156
- ]
778
+ // src/hooks/useGoogleClassroom.ts
779
+ var useGoogleClassroom = () => {
780
+ const submitAssignmentToGoogleClassroom = async ({
781
+ assignment,
782
+ scores,
783
+ googleUserId = null
784
+ // optional to override the user's googleUserId
785
+ }) => {
786
+ var _a, _b, _c;
787
+ try {
788
+ const { googleClassroomUserId = null } = scores;
789
+ const googleId = googleUserId || googleClassroomUserId;
790
+ if (!googleId)
791
+ return {
792
+ error: true,
793
+ message: "No Google Classroom ID found"
794
+ };
795
+ const { courseWorkId, maxPoints, owners, courseId } = assignment;
796
+ const draftGrade = (scores == null ? void 0 : scores.score) ? (scores == null ? void 0 : scores.score) / 100 * maxPoints : 0;
797
+ const result = await ((_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "submitAssignmentToGoogleClassroomV2")) == null ? void 0 : _c({
798
+ teacherId: owners[0],
799
+ courseId,
800
+ courseWorkId,
801
+ userId: googleId,
802
+ draftGrade
803
+ }));
804
+ return result;
805
+ } catch (error) {
806
+ return { error: true, message: error.message };
807
+ }
808
+ };
809
+ return {
810
+ submitAssignmentToGoogleClassroom
1157
811
  };
1158
- if (standard === "wida") {
1159
- const wida_level = {
1160
- type: "number",
1161
- enum: [1, 2, 3, 4, 5, 6],
1162
- 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
1163
-
1164
- 1 - Entering
1165
- 2 - Emerging
1166
- 3 - Developing
1167
- 4 - Expanding
1168
- 5 - Bridging
1169
- 6 - Reaching
1170
-
1171
- 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.
1172
- `
1173
- };
1174
- const wida_justification = {
1175
- type: "string",
1176
- description: `An explanation of the rationale behind the assigned WIDA level of the response, considering both accuracy and fluency. WRITE THIS IN ENGLISH!`
1177
- };
1178
- tool.tools[0].function.parameters.required.push("wida_level");
1179
- tool.tools[0].function.parameters.required.push("wida_justification");
1180
- tool.tools[0].function.parameters.properties.wida_level = wida_level;
1181
- tool.tools[0].function.parameters.properties.wida_justification = wida_justification;
1182
- } else {
1183
- const actfl_level = {
1184
- type: "string",
1185
- enum: ["NL", "NM", "NH", "IL", "IM", "IH", "AL", "AM", "AH", "S", "D"],
1186
- 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"
1187
- };
1188
- const actfl_justification = {
1189
- type: "string",
1190
- description: "An explanation of the rationale behind the assigned ACTFL level, considering both accuracy and fluency"
1191
- };
1192
- tool.tools[0].function.parameters.required.push("actfl_level");
1193
- tool.tools[0].function.parameters.required.push("actfl_justification");
1194
- tool.tools[0].function.parameters.properties.actfl_level = actfl_level;
1195
- tool.tools[0].function.parameters.properties.actfl_justification = actfl_justification;
1196
- }
1197
- return tool;
1198
812
  };
1199
813
 
1200
- // src/utils/debounce.utils.ts
1201
- function debounce(func, waitFor) {
1202
- let timeoutId;
1203
- return (...args) => new Promise((resolve, reject) => {
1204
- if (timeoutId) {
1205
- clearTimeout(timeoutId);
1206
- }
1207
- timeoutId = setTimeout(async () => {
1208
- try {
1209
- const result = await func(...args);
1210
- resolve(result);
1211
- } catch (error) {
1212
- reject(error);
1213
- }
1214
- }, waitFor);
1215
- });
1216
- }
1217
-
1218
- // src/domains/assignment/hooks/score-hooks.ts
1219
- import { useMutation as useMutation2, useQuery as useQuery4 } from "@tanstack/react-query";
1220
-
1221
- // src/lib/tanstack/handle-optimistic-update-query.ts
1222
- var handleOptimisticUpdate = async ({
1223
- queryClient,
1224
- queryKey,
1225
- newData
1226
- }) => {
1227
- await queryClient.cancelQueries({
1228
- queryKey
1229
- });
1230
- const previousData = queryClient.getQueryData(queryKey);
1231
- if (previousData === void 0) {
1232
- queryClient.setQueryData(queryKey, newData);
1233
- } else {
1234
- queryClient.setQueryData(queryKey, { ...previousData, ...newData });
814
+ // src/lib/firebase/firebase-analytics/grading-standard.ts
815
+ var logGradingStandardLog = (data) => {
816
+ var _a, _b, _c;
817
+ if (data.courseId && data.type && data.level) {
818
+ (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "handleCouresAnalyticsEvent")) == null ? void 0 : _c({
819
+ eventType: data.type || "custom",
820
+ level: data.level,
821
+ courseId: data.courseId
822
+ });
1235
823
  }
1236
- return { previousData };
1237
- };
1238
-
1239
- // src/constants/speakable-plans.ts
1240
- var FEEDBACK_PLANS = {
1241
- FEEDBACK_TRANSCRIPT: "FEEDBACK_TRANSCRIPT",
1242
- // Transcript from the audio
1243
- FEEDBACK_SUMMARY: "FEEDBACK_SUMMARY",
1244
- // Chatty summary (Free plan)
1245
- FEEDBACK_GRAMMAR_INSIGHTS: "FEEDBACK_GRAMMAR_INSIGHTS",
1246
- // Grammar insights
1247
- FEEDBACK_SUGGESTED_RESPONSE: "FEEDBACK_SUGGESTED_RESPONSE",
1248
- // Suggested Response
1249
- FEEDBACK_RUBRIC: "FEEDBACK_RUBRIC",
1250
- // Suggested Response
1251
- FEEDBACK_GRADING_STANDARDS: "FEEDBACK_GRADING_STANDARDS",
1252
- // ACTFL / WIDA Estimate
1253
- FEEDBACK_TARGET_LANGUAGE: "FEEDBACK_TARGET_LANGUAGE",
1254
- // Ability to set the feedback language to the target language of the student
1255
- FEEDBACK_DISABLE_ALLOW_RETRIES: "FEEDBACK_DISABLE_ALLOW_RETRIES"
1256
- // Turn of allow retries
1257
- };
1258
- var AUTO_GRADING_PLANS = {
1259
- AUTO_GRADING_PASS_FAIL: "AUTO_GRADING_PASS_FAIL",
1260
- // Pass / fail grading
1261
- AUTO_GRADING_RUBRICS: "AUTO_GRADING_RUBRICS",
1262
- // Autograded rubrics
1263
- AUTO_GRADING_STANDARDS_BASED: "AUTO_GRADING_STANDARDS_BASED"
1264
- // Standards based grading
1265
- };
1266
- var AI_ASSISTANT_PLANS = {
1267
- AI_ASSISTANT_DOCUMENT_UPLOADS: "AI_ASSISTANT_DOCUMENT_UPLOADS",
1268
- // Allow document uploading
1269
- AI_ASSISTANT_UNLIMITED_USE: "AI_ASSISTANT_UNLIMITED_USE"
1270
- // Allow unlimited use of AI assistant. Otherwise, limits are used.
1271
- };
1272
- var ASSIGNMENT_SETTINGS_PLANS = {
1273
- ASSESSMENTS: "ASSESSMENTS",
1274
- // Ability to create assessment assignment types
1275
- GOOGLE_CLASSROOM_GRADE_PASSBACK: "GOOGLE_CLASSROOM_GRADE_PASSBACK"
1276
- // Assignment scores can sync with classroom
1277
- };
1278
- var ANALYTICS_PLANS = {
1279
- ANALYTICS_GRADEBOOK: "ANALYTICS_GRADEBOOK",
1280
- // Access to the gradebook page
1281
- ANALYTICS_CLASSROOM_ANALYTICS: "ANALYTICS_CLASSROOM_ANALYTICS",
1282
- // Access to the classroom analytics page
1283
- ANALYTICS_STUDENT_PROGRESS_REPORTS: "ANALYTICS_STUDENT_PROGRESS_REPORTS",
1284
- // Access to the panel that shows an individual student's progress and assignments
1285
- ANALYTICS_ASSIGNMENT_RESULTS: "ANALYTICS_ASSIGNMENT_RESULTS",
1286
- // Access to the assigment RESULTS page
1287
- ANALYTICS_ORGANIZATION: "ANALYTICS_ORGANIZATION"
1288
- // Access to the organization analytics panel (for permitted admins)
1289
- };
1290
- var SPACES_PLANS = {
1291
- SPACES_CREATE_SPACE: "SPACES_CREATE_SPACE",
1292
- // Ability to create spaces
1293
- SPACES_CHECK_POINTS: "SPACES_CHECK_POINTS"
1294
- // Feature not available yet. Ability to create checkpoints for spaces for data aggregation
1295
- };
1296
- var DISCOVER_PLANS = {
1297
- DISCOVER_ORGANIZATION_LIBRARY: "DISCOVER_ORGANIZATION_LIBRARY"
1298
- // Access to the organizations shared library
1299
- };
1300
- var MEDIA_AREA_PLANS = {
1301
- MEDIA_AREA_DOCUMENT_UPLOAD: "MEDIA_AREA_DOCUMENT_UPLOAD",
1302
- MEDIA_AREA_AUDIO_FILES: "MEDIA_AREA_AUDIO_FILES"
1303
- };
1304
- var FREE_PLAN = [];
1305
- var TEACHER_PRO_PLAN = [
1306
- FEEDBACK_PLANS.FEEDBACK_TRANSCRIPT,
1307
- FEEDBACK_PLANS.FEEDBACK_SUMMARY,
1308
- FEEDBACK_PLANS.FEEDBACK_TARGET_LANGUAGE,
1309
- AUTO_GRADING_PLANS.AUTO_GRADING_PASS_FAIL,
1310
- ANALYTICS_PLANS.ANALYTICS_GRADEBOOK,
1311
- SPACES_PLANS.SPACES_CREATE_SPACE
1312
- // AUTO_GRADING_PLANS.AUTO_GRADING_STANDARDS_BASED,
1313
- ];
1314
- var SCHOOL_STARTER = [
1315
- FEEDBACK_PLANS.FEEDBACK_TRANSCRIPT,
1316
- FEEDBACK_PLANS.FEEDBACK_SUMMARY,
1317
- FEEDBACK_PLANS.FEEDBACK_GRAMMAR_INSIGHTS,
1318
- FEEDBACK_PLANS.FEEDBACK_SUGGESTED_RESPONSE,
1319
- FEEDBACK_PLANS.FEEDBACK_RUBRIC,
1320
- FEEDBACK_PLANS.FEEDBACK_GRADING_STANDARDS,
1321
- FEEDBACK_PLANS.FEEDBACK_DISABLE_ALLOW_RETRIES,
1322
- FEEDBACK_PLANS.FEEDBACK_TARGET_LANGUAGE,
1323
- AUTO_GRADING_PLANS.AUTO_GRADING_PASS_FAIL,
1324
- AUTO_GRADING_PLANS.AUTO_GRADING_RUBRICS,
1325
- AUTO_GRADING_PLANS.AUTO_GRADING_STANDARDS_BASED,
1326
- AI_ASSISTANT_PLANS.AI_ASSISTANT_DOCUMENT_UPLOADS,
1327
- AI_ASSISTANT_PLANS.AI_ASSISTANT_UNLIMITED_USE,
1328
- // ASSIGNMENT_SETTINGS_PLANS.ASSESSMENTS,
1329
- ASSIGNMENT_SETTINGS_PLANS.GOOGLE_CLASSROOM_GRADE_PASSBACK,
1330
- ANALYTICS_PLANS.ANALYTICS_GRADEBOOK,
1331
- ANALYTICS_PLANS.ANALYTICS_STUDENT_PROGRESS_REPORTS,
1332
- ANALYTICS_PLANS.ANALYTICS_CLASSROOM_ANALYTICS,
1333
- // ANALYTICS_PLANS.ANALYTICS_ORGANIZATION,
1334
- SPACES_PLANS.SPACES_CREATE_SPACE,
1335
- SPACES_PLANS.SPACES_CHECK_POINTS,
1336
- // DISCOVER_PLANS.DISCOVER_ORGANIZATION_LIBRARY,
1337
- MEDIA_AREA_PLANS.MEDIA_AREA_DOCUMENT_UPLOAD,
1338
- MEDIA_AREA_PLANS.MEDIA_AREA_AUDIO_FILES
1339
- ];
1340
- var ORGANIZATION_PLAN = [
1341
- FEEDBACK_PLANS.FEEDBACK_TRANSCRIPT,
1342
- FEEDBACK_PLANS.FEEDBACK_SUMMARY,
1343
- FEEDBACK_PLANS.FEEDBACK_GRAMMAR_INSIGHTS,
1344
- FEEDBACK_PLANS.FEEDBACK_SUGGESTED_RESPONSE,
1345
- FEEDBACK_PLANS.FEEDBACK_RUBRIC,
1346
- FEEDBACK_PLANS.FEEDBACK_GRADING_STANDARDS,
1347
- FEEDBACK_PLANS.FEEDBACK_DISABLE_ALLOW_RETRIES,
1348
- FEEDBACK_PLANS.FEEDBACK_TARGET_LANGUAGE,
1349
- AUTO_GRADING_PLANS.AUTO_GRADING_PASS_FAIL,
1350
- AUTO_GRADING_PLANS.AUTO_GRADING_RUBRICS,
1351
- AUTO_GRADING_PLANS.AUTO_GRADING_STANDARDS_BASED,
1352
- AI_ASSISTANT_PLANS.AI_ASSISTANT_DOCUMENT_UPLOADS,
1353
- AI_ASSISTANT_PLANS.AI_ASSISTANT_UNLIMITED_USE,
1354
- ASSIGNMENT_SETTINGS_PLANS.ASSESSMENTS,
1355
- ASSIGNMENT_SETTINGS_PLANS.GOOGLE_CLASSROOM_GRADE_PASSBACK,
1356
- ANALYTICS_PLANS.ANALYTICS_GRADEBOOK,
1357
- ANALYTICS_PLANS.ANALYTICS_STUDENT_PROGRESS_REPORTS,
1358
- ANALYTICS_PLANS.ANALYTICS_CLASSROOM_ANALYTICS,
1359
- ANALYTICS_PLANS.ANALYTICS_ORGANIZATION,
1360
- SPACES_PLANS.SPACES_CREATE_SPACE,
1361
- SPACES_PLANS.SPACES_CHECK_POINTS,
1362
- DISCOVER_PLANS.DISCOVER_ORGANIZATION_LIBRARY,
1363
- MEDIA_AREA_PLANS.MEDIA_AREA_DOCUMENT_UPLOAD,
1364
- MEDIA_AREA_PLANS.MEDIA_AREA_AUDIO_FILES
1365
- ];
1366
- var SpeakablePlanTypes = {
1367
- basic: "basic",
1368
- teacher_pro: "teacher_pro",
1369
- school_starter: "school_starter",
1370
- organization: "organization",
1371
- // OLD PLANS
1372
- starter: "starter",
1373
- growth: "growth",
1374
- professional: "professional"
1375
- };
1376
- var SpeakablePermissionsMap = {
1377
- [SpeakablePlanTypes.basic]: FREE_PLAN,
1378
- [SpeakablePlanTypes.starter]: TEACHER_PRO_PLAN,
1379
- [SpeakablePlanTypes.teacher_pro]: TEACHER_PRO_PLAN,
1380
- [SpeakablePlanTypes.growth]: ORGANIZATION_PLAN,
1381
- [SpeakablePlanTypes.professional]: ORGANIZATION_PLAN,
1382
- [SpeakablePlanTypes.organization]: ORGANIZATION_PLAN,
1383
- [SpeakablePlanTypes.school_starter]: SCHOOL_STARTER
1384
- };
1385
- var SpeakablePlanHierarchy = [
1386
- SpeakablePlanTypes.basic,
1387
- SpeakablePlanTypes.starter,
1388
- SpeakablePlanTypes.teacher_pro,
1389
- SpeakablePlanTypes.growth,
1390
- SpeakablePlanTypes.professional,
1391
- SpeakablePlanTypes.school_starter,
1392
- SpeakablePlanTypes.organization
1393
- ];
1394
-
1395
- // src/hooks/usePermissions.ts
1396
- var usePermissions = () => {
1397
- const { permissions } = useSpeakableApi();
1398
- const has = (permission) => {
1399
- var _a;
1400
- return (_a = permissions.permissions) == null ? void 0 : _a.includes(permission);
1401
- };
1402
- return {
1403
- plan: permissions.plan,
1404
- permissionsLoaded: permissions.loaded,
1405
- isStripePlan: permissions.isStripePlan,
1406
- refreshDate: permissions.refreshDate,
1407
- isInstitutionPlan: permissions.isInstitutionPlan,
1408
- subscriptionId: permissions.subscriptionId,
1409
- contact: permissions.contact,
1410
- hasGradebook: has(ANALYTICS_PLANS.ANALYTICS_GRADEBOOK),
1411
- hasGoogleClassroomGradePassback: has(ASSIGNMENT_SETTINGS_PLANS.GOOGLE_CLASSROOM_GRADE_PASSBACK),
1412
- hasAssessments: has(ASSIGNMENT_SETTINGS_PLANS.ASSESSMENTS),
1413
- hasSectionAnalytics: has(ANALYTICS_PLANS.ANALYTICS_CLASSROOM_ANALYTICS),
1414
- hasStudentReports: has(ANALYTICS_PLANS.ANALYTICS_STUDENT_PROGRESS_REPORTS),
1415
- permissions: permissions || [],
1416
- hasStudentPortfolios: permissions.hasStudentPortfolios,
1417
- isFreeOrgTrial: permissions.type === "free_org_trial",
1418
- freeOrgTrialExpired: permissions.freeOrgTrialExpired
1419
- };
1420
- };
1421
- var usePermissions_default = usePermissions;
1422
-
1423
- // src/hooks/useGoogleClassroom.ts
1424
- var useGoogleClassroom = () => {
1425
- const submitAssignmentToGoogleClassroom = async ({
1426
- assignment,
1427
- scores,
1428
- googleUserId = null
1429
- // optional to override the user's googleUserId
1430
- }) => {
1431
- var _a, _b, _c;
1432
- try {
1433
- const { googleClassroomUserId = null } = scores;
1434
- const googleId = googleUserId || googleClassroomUserId;
1435
- if (!googleId)
1436
- return {
1437
- error: true,
1438
- message: "No Google Classroom ID found"
1439
- };
1440
- const { courseWorkId, maxPoints, owners, courseId } = assignment;
1441
- const draftGrade = (scores == null ? void 0 : scores.score) ? (scores == null ? void 0 : scores.score) / 100 * maxPoints : 0;
1442
- const result = await ((_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "submitAssignmentToGoogleClassroomV2")) == null ? void 0 : _c({
1443
- teacherId: owners[0],
1444
- courseId,
1445
- courseWorkId,
1446
- userId: googleId,
1447
- draftGrade
1448
- }));
1449
- return result;
1450
- } catch (error) {
1451
- return { error: true, message: error.message };
1452
- }
1453
- };
1454
- return {
1455
- submitAssignmentToGoogleClassroom
1456
- };
1457
- };
1458
-
1459
- // src/lib/firebase/firebase-analytics/grading-standard.ts
1460
- var logGradingStandardLog = (data) => {
1461
- var _a, _b, _c;
1462
- if (data.courseId && data.type && data.level) {
1463
- (_c = (_b = (_a = api).httpsCallable) == null ? void 0 : _b.call(_a, "handleCouresAnalyticsEvent")) == null ? void 0 : _c({
1464
- eventType: data.type || "custom",
1465
- level: data.level,
1466
- courseId: data.courseId
1467
- });
1468
- }
1469
- api.logEvent("logGradingStandard", data);
824
+ api.logEvent("logGradingStandard", data);
1470
825
  };
1471
826
 
1472
827
  // src/constants/analytics.constants.ts
@@ -1868,7 +1223,7 @@ function useScore({
1868
1223
  enabled = true,
1869
1224
  googleClassroomUserId
1870
1225
  }) {
1871
- return useQuery4({
1226
+ return useQuery2({
1872
1227
  queryFn: () => getScore({
1873
1228
  userId,
1874
1229
  courseId,
@@ -1883,7 +1238,7 @@ function useScore({
1883
1238
  var debounceUpdateScore = debounce(updateScore, 1e3);
1884
1239
  function useUpdateScore() {
1885
1240
  const { queryClient } = useSpeakableApi();
1886
- const mutation = useMutation2({
1241
+ const mutation = useMutation({
1887
1242
  mutationFn: debounceUpdateScore,
1888
1243
  onMutate: (variables) => {
1889
1244
  return handleOptimisticUpdate({
@@ -1915,7 +1270,7 @@ function useUpdateCardScore({
1915
1270
  }) {
1916
1271
  const { queryClient } = useSpeakableApi();
1917
1272
  const queryKey = scoreQueryKeys.byId(activityId);
1918
- const mutation = useMutation2({
1273
+ const mutation = useMutation({
1919
1274
  mutationFn: async ({ cardId, cardScore }) => {
1920
1275
  const previousScores = queryClient.getQueryData(queryKey);
1921
1276
  const { progress, score, newScoreUpdated, updatedCardScore } = getScoreUpdated({
@@ -2023,7 +1378,7 @@ var handleOptimisticScore = ({
2023
1378
  };
2024
1379
  function useClearScore() {
2025
1380
  const { queryClient } = useSpeakableApi();
2026
- const mutation = useMutation2({
1381
+ const mutation = useMutation({
2027
1382
  mutationFn: clearScore,
2028
1383
  onSettled: (result) => {
2029
1384
  var _a;
@@ -2044,7 +1399,7 @@ function useSubmitAssignmentScore({
2044
1399
  const { hasGoogleClassroomGradePassback } = usePermissions_default();
2045
1400
  const { submitAssignmentToGoogleClassroom } = useGoogleClassroom();
2046
1401
  const { createNotification: createNotification2 } = useCreateNotification();
2047
- const mutation = useMutation2({
1402
+ const mutation = useMutation({
2048
1403
  mutationFn: async ({
2049
1404
  assignment,
2050
1405
  userId,
@@ -2100,7 +1455,7 @@ function useSubmitAssignmentScore({
2100
1455
  }
2101
1456
  function useSubmitPracticeScore() {
2102
1457
  const { queryClient } = useSpeakableApi();
2103
- const mutation = useMutation2({
1458
+ const mutation = useMutation({
2104
1459
  mutationFn: async ({
2105
1460
  setId,
2106
1461
  userId,
@@ -2133,6 +1488,651 @@ function useSubmitPracticeScore() {
2133
1488
  };
2134
1489
  }
2135
1490
 
1491
+ // src/domains/cards/card.hooks.ts
1492
+ import { useMutation as useMutation2, useQueries, useQuery as useQuery3 } from "@tanstack/react-query";
1493
+ import { useMemo } from "react";
1494
+
1495
+ // src/domains/cards/card.constants.ts
1496
+ var FeedbackTypesCard = /* @__PURE__ */ ((FeedbackTypesCard2) => {
1497
+ FeedbackTypesCard2["SuggestedResponse"] = "suggested_response";
1498
+ FeedbackTypesCard2["Wida"] = "wida";
1499
+ FeedbackTypesCard2["GrammarInsights"] = "grammar_insights";
1500
+ FeedbackTypesCard2["Actfl"] = "actfl";
1501
+ FeedbackTypesCard2["ProficiencyLevel"] = "proficiency_level";
1502
+ return FeedbackTypesCard2;
1503
+ })(FeedbackTypesCard || {});
1504
+ var LeniencyCard = /* @__PURE__ */ ((LeniencyCard2) => {
1505
+ LeniencyCard2["CONFIDENCE"] = "confidence";
1506
+ LeniencyCard2["EASY"] = "easy";
1507
+ LeniencyCard2["NORMAL"] = "normal";
1508
+ LeniencyCard2["HARD"] = "hard";
1509
+ return LeniencyCard2;
1510
+ })(LeniencyCard || {});
1511
+ var LENIENCY_OPTIONS = [
1512
+ {
1513
+ label: "Build Confidence - most lenient",
1514
+ value: "confidence" /* CONFIDENCE */
1515
+ },
1516
+ {
1517
+ label: "Very Lenient",
1518
+ value: "easy" /* EASY */
1519
+ },
1520
+ {
1521
+ label: "Normal",
1522
+ value: "normal" /* NORMAL */
1523
+ },
1524
+ {
1525
+ label: "No leniency - most strict",
1526
+ value: "hard" /* HARD */
1527
+ }
1528
+ ];
1529
+ var STUDENT_LEVELS_OPTIONS = [
1530
+ {
1531
+ label: "Beginner",
1532
+ description: "Beginner Level: Just starting out. Can say a few basic words and phrases.",
1533
+ value: "beginner"
1534
+ },
1535
+ {
1536
+ label: "Elementary",
1537
+ description: "Elementary Level: Can understand simple sentences and have very basic conversations.",
1538
+ value: "elementary"
1539
+ },
1540
+ {
1541
+ label: "Intermediate",
1542
+ description: "Intermediate Level: Can talk about everyday topics and handle common situations.",
1543
+ value: "intermediate"
1544
+ },
1545
+ {
1546
+ label: "Advanced",
1547
+ description: "Advanced Level: Can speak and understand with ease, and explain ideas clearly.",
1548
+ value: "advanced"
1549
+ },
1550
+ {
1551
+ label: "Fluent",
1552
+ description: "Fluent Level: Speaks naturally and easily. Can use the language in work or school settings.",
1553
+ value: "fluent"
1554
+ },
1555
+ {
1556
+ label: "Native-like",
1557
+ description: "Native-like Level: Understands and speaks like a native. Can discuss complex ideas accurately.",
1558
+ value: "nativeLike"
1559
+ }
1560
+ ];
1561
+ var BASE_RESPOND_FIELD_VALUES = {
1562
+ title: "",
1563
+ allowRetries: true,
1564
+ respondTime: 180,
1565
+ maxCharacters: 1e3
1566
+ };
1567
+ var BASE_REPEAT_FIELD_VALUES = {
1568
+ repeat: 1
1569
+ };
1570
+ var BASE_MULTIPLE_CHOICE_FIELD_VALUES = {
1571
+ MCQType: "single",
1572
+ answer: ["A"],
1573
+ choices: [
1574
+ { option: "A", value: "Option A" },
1575
+ { option: "B", value: "Option B" },
1576
+ { option: "C", value: "Option C" }
1577
+ ]
1578
+ };
1579
+ var VerificationCardStatus = /* @__PURE__ */ ((VerificationCardStatus2) => {
1580
+ VerificationCardStatus2["VERIFIED"] = "VERIFIED";
1581
+ VerificationCardStatus2["WARNING"] = "WARNING";
1582
+ VerificationCardStatus2["NOT_RECOMMENDED"] = "NOT_RECOMMENDED";
1583
+ VerificationCardStatus2["NOT_WORKING"] = "NOT_WORKING";
1584
+ VerificationCardStatus2["NOT_CHECKED"] = "NOT_CHECKED";
1585
+ return VerificationCardStatus2;
1586
+ })(VerificationCardStatus || {});
1587
+ var CARDS_COLLECTION = "flashcards";
1588
+ var refsCardsFiresotre = {
1589
+ allCards: CARDS_COLLECTION,
1590
+ card: (id) => `${CARDS_COLLECTION}/${id}`
1591
+ };
1592
+
1593
+ // src/domains/cards/services/get-card.service.ts
1594
+ async function _getCard(params) {
1595
+ const ref = refsCardsFiresotre.card(params.cardId);
1596
+ const response = await api.getDoc(ref);
1597
+ if (!response.data) return null;
1598
+ return response.data;
1599
+ }
1600
+ var getCard = withErrorHandler(_getCard, "getCard");
1601
+
1602
+ // src/domains/cards/services/create-card.service.ts
1603
+ import { v4 } from "uuid";
1604
+
1605
+ // src/domains/cards/card.model.ts
1606
+ var CardActivityType = /* @__PURE__ */ ((CardActivityType2) => {
1607
+ CardActivityType2["READ_REPEAT"] = "READ_REPEAT";
1608
+ CardActivityType2["VIDEO"] = "VIDEO";
1609
+ CardActivityType2["TEXT"] = "TEXT";
1610
+ CardActivityType2["READ_RESPOND"] = "READ_RESPOND";
1611
+ CardActivityType2["FREE_RESPONSE"] = "FREE_RESPONSE";
1612
+ CardActivityType2["REPEAT"] = "REPEAT";
1613
+ CardActivityType2["RESPOND"] = "RESPOND";
1614
+ CardActivityType2["RESPOND_WRITE"] = "RESPOND_WRITE";
1615
+ CardActivityType2["TEXT_TO_SPEECH"] = "TEXT_TO_SPEECH";
1616
+ CardActivityType2["MULTIPLE_CHOICE"] = "MULTIPLE_CHOICE";
1617
+ CardActivityType2["PODCAST"] = "PODCAST";
1618
+ CardActivityType2["MEDIA_PAGE"] = "MEDIA_PAGE";
1619
+ CardActivityType2["WRITE"] = "WRITE";
1620
+ CardActivityType2["SHORT_ANSWER"] = "SHORT_ANSWER";
1621
+ CardActivityType2["SHORT_STORY"] = "SHORT_STORY";
1622
+ CardActivityType2["SPEAK"] = "SPEAK";
1623
+ CardActivityType2["CONVERSATION"] = "CONVERSATION";
1624
+ CardActivityType2["CONVERSATION_WRITE"] = "CONVERSATION_WRITE";
1625
+ CardActivityType2["DIALOGUE"] = "DIALOGUE";
1626
+ CardActivityType2["INSTRUCTION"] = "INSTRUCTION";
1627
+ CardActivityType2["LISTEN"] = "LISTEN";
1628
+ CardActivityType2["READ"] = "READ";
1629
+ CardActivityType2["ANSWER"] = "ANSWER";
1630
+ return CardActivityType2;
1631
+ })(CardActivityType || {});
1632
+ var RESPOND_CARD_ACTIVITY_TYPES = [
1633
+ "READ_RESPOND" /* READ_RESPOND */,
1634
+ "RESPOND" /* RESPOND */,
1635
+ "RESPOND_WRITE" /* RESPOND_WRITE */,
1636
+ "FREE_RESPONSE" /* FREE_RESPONSE */
1637
+ ];
1638
+ var MULTIPLE_CHOICE_CARD_ACTIVITY_TYPES = ["MULTIPLE_CHOICE" /* MULTIPLE_CHOICE */];
1639
+ var REPEAT_CARD_ACTIVITY_TYPES = ["READ_REPEAT" /* READ_REPEAT */, "REPEAT" /* REPEAT */];
1640
+ var RESPOND_WRITE_CARD_ACTIVITY_TYPES = [
1641
+ "RESPOND_WRITE" /* RESPOND_WRITE */,
1642
+ "FREE_RESPONSE" /* FREE_RESPONSE */
1643
+ ];
1644
+ var RESPOND_AUDIO_CARD_ACTIVITY_TYPES = [
1645
+ "RESPOND" /* RESPOND */,
1646
+ "READ_RESPOND" /* READ_RESPOND */
1647
+ ];
1648
+ var ALLOWED_CARD_ACTIVITY_TYPES_FOR_SUMMARY = [
1649
+ "REPEAT" /* REPEAT */,
1650
+ "RESPOND" /* RESPOND */,
1651
+ "READ_REPEAT" /* READ_REPEAT */,
1652
+ "READ_RESPOND" /* READ_RESPOND */,
1653
+ "FREE_RESPONSE" /* FREE_RESPONSE */,
1654
+ "RESPOND_WRITE" /* RESPOND_WRITE */,
1655
+ "MULTIPLE_CHOICE" /* MULTIPLE_CHOICE */
1656
+ ];
1657
+
1658
+ // src/utils/text-utils.ts
1659
+ import sha1 from "js-sha1";
1660
+ var purify = (word) => {
1661
+ 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();
1662
+ };
1663
+ var cleanString = (words) => {
1664
+ const splitWords = words == null ? void 0 : words.split("+");
1665
+ if (splitWords && splitWords.length === 1) {
1666
+ const newWord = purify(words);
1667
+ return newWord;
1668
+ } else if (splitWords && splitWords.length > 1) {
1669
+ const split = splitWords.map((w) => purify(w));
1670
+ return split;
1671
+ } else {
1672
+ return "";
1673
+ }
1674
+ };
1675
+ var getWordHash = (word, language) => {
1676
+ const cleanedWord = cleanString(word);
1677
+ const wordHash = sha1(`${language}-${cleanedWord}`);
1678
+ console.log("wordHash core library", wordHash);
1679
+ return wordHash;
1680
+ };
1681
+
1682
+ // src/domains/cards/services/get-card-verification-status.service.ts
1683
+ var charactarLanguages = ["zh", "ja", "ko"];
1684
+ var getVerificationStatus = async (target_text, language) => {
1685
+ if ((target_text == null ? void 0 : target_text.length) < 3 && !charactarLanguages.includes(language)) {
1686
+ return "NOT_RECOMMENDED" /* NOT_RECOMMENDED */;
1687
+ }
1688
+ const hash = getWordHash(target_text, language);
1689
+ const response = await api.getDoc(`checked-pronunciations/${hash}`);
1690
+ try {
1691
+ if (response.data) {
1692
+ return processRecord(response.data);
1693
+ } else {
1694
+ return "NOT_CHECKED" /* NOT_CHECKED */;
1695
+ }
1696
+ } catch (e) {
1697
+ return "NOT_CHECKED" /* NOT_CHECKED */;
1698
+ }
1699
+ };
1700
+ var processRecord = (data) => {
1701
+ const { pronunciations = 0, fails = 0 } = data;
1702
+ const attempts = pronunciations + fails;
1703
+ const successRate = attempts > 0 ? pronunciations / attempts * 100 : 0;
1704
+ let newStatus = null;
1705
+ if (attempts < 6) {
1706
+ return "NOT_CHECKED" /* NOT_CHECKED */;
1707
+ }
1708
+ if (successRate > 25) {
1709
+ newStatus = "VERIFIED" /* VERIFIED */;
1710
+ } else if (successRate > 10) {
1711
+ newStatus = "WARNING" /* WARNING */;
1712
+ } else if (fails > 20 && successRate < 10 && pronunciations > 1) {
1713
+ newStatus = "NOT_RECOMMENDED" /* NOT_RECOMMENDED */;
1714
+ } else if (pronunciations === 0 && fails > 20) {
1715
+ newStatus = "NOT_WORKING" /* NOT_WORKING */;
1716
+ } else {
1717
+ newStatus = "NOT_CHECKED" /* NOT_CHECKED */;
1718
+ }
1719
+ return newStatus;
1720
+ };
1721
+
1722
+ // src/domains/cards/services/create-card.service.ts
1723
+ async function _createCard({ data }) {
1724
+ const response = await api.addDoc(refsCardsFiresotre.allCards, data);
1725
+ return response;
1726
+ }
1727
+ var createCard = withErrorHandler(_createCard, "createCard");
1728
+ async function _createCards({ cards }) {
1729
+ const { writeBatch: writeBatch2, doc: doc2 } = api.accessHelpers();
1730
+ const batch = writeBatch2();
1731
+ const cardsWithId = [];
1732
+ for (const card of cards) {
1733
+ const cardId = v4();
1734
+ const ref = doc2(refsCardsFiresotre.card(cardId));
1735
+ const newCardObject = {
1736
+ ...card,
1737
+ id: cardId
1738
+ };
1739
+ if (card.type === "READ_REPEAT" /* READ_REPEAT */ && card.target_text && card.language) {
1740
+ const verificationStatus = await getVerificationStatus(card.target_text, card.language);
1741
+ newCardObject.verificationStatus = verificationStatus || null;
1742
+ }
1743
+ cardsWithId.push(newCardObject);
1744
+ batch.set(ref, newCardObject);
1745
+ }
1746
+ await batch.commit();
1747
+ return cardsWithId;
1748
+ }
1749
+ var createCards = withErrorHandler(_createCards, "createCards");
1750
+
1751
+ // src/domains/cards/card.hooks.ts
1752
+ var cardsQueryKeys = {
1753
+ all: ["cards"],
1754
+ one: (params) => [...cardsQueryKeys.all, params.cardId]
1755
+ };
1756
+ function useCards({
1757
+ cardIds,
1758
+ enabled = true,
1759
+ asObject
1760
+ }) {
1761
+ const queries = useQueries({
1762
+ queries: cardIds.map((cardId) => ({
1763
+ enabled: enabled && cardIds.length > 0,
1764
+ queryKey: cardsQueryKeys.one({
1765
+ cardId
1766
+ }),
1767
+ queryFn: () => getCard({ cardId })
1768
+ }))
1769
+ });
1770
+ const cards = queries.map((query2) => query2.data).filter(Boolean);
1771
+ const cardsObject = useMemo(() => {
1772
+ if (!asObject) return null;
1773
+ return cards.reduce((acc, card) => {
1774
+ acc[card.id] = card;
1775
+ return acc;
1776
+ }, {});
1777
+ }, [asObject, cards]);
1778
+ return {
1779
+ cards,
1780
+ cardsObject,
1781
+ cardsQueries: queries
1782
+ };
1783
+ }
1784
+ function useCreateCard() {
1785
+ const { queryClient } = useSpeakableApi();
1786
+ const mutationCreateCard = useMutation2({
1787
+ mutationFn: createCard,
1788
+ onSuccess: (cardCreated) => {
1789
+ queryClient.invalidateQueries({ queryKey: cardsQueryKeys.one({ cardId: cardCreated.id }) });
1790
+ }
1791
+ });
1792
+ return {
1793
+ mutationCreateCard
1794
+ };
1795
+ }
1796
+ function useCreateCards() {
1797
+ const mutationCreateCards = useMutation2({
1798
+ mutationFn: createCards
1799
+ });
1800
+ return {
1801
+ mutationCreateCards
1802
+ };
1803
+ }
1804
+ function getCardFromCache({
1805
+ cardId,
1806
+ queryClient
1807
+ }) {
1808
+ return queryClient.getQueryData(cardsQueryKeys.one({ cardId }));
1809
+ }
1810
+ function updateCardInCache({
1811
+ cardId,
1812
+ card,
1813
+ queryClient
1814
+ }) {
1815
+ queryClient.setQueryData(cardsQueryKeys.one({ cardId }), card);
1816
+ }
1817
+ function useGetCard({ cardId }) {
1818
+ const query2 = useQuery3({
1819
+ queryKey: cardsQueryKeys.one({ cardId }),
1820
+ queryFn: () => getCard({ cardId })
1821
+ });
1822
+ return query2;
1823
+ }
1824
+
1825
+ // src/domains/cards/card.repo.ts
1826
+ var createCardRepo = () => {
1827
+ return {
1828
+ createCard,
1829
+ createCards,
1830
+ getCard
1831
+ };
1832
+ };
1833
+
1834
+ // src/domains/sets/set.hooks.ts
1835
+ import { useQuery as useQuery4 } from "@tanstack/react-query";
1836
+
1837
+ // src/domains/sets/set.constants.ts
1838
+ var SETS_COLLECTION = "sets";
1839
+ var refsSetsFirestore = {
1840
+ allSets: SETS_COLLECTION,
1841
+ set: (id) => `${SETS_COLLECTION}/${id}`
1842
+ };
1843
+
1844
+ // src/domains/sets/services/get-set.service.ts
1845
+ async function _getSet({ setId }) {
1846
+ const response = await api.getDoc(refsSetsFirestore.set(setId));
1847
+ return response.data;
1848
+ }
1849
+ var getSet = withErrorHandler(_getSet, "getSet");
1850
+
1851
+ // src/domains/sets/set.hooks.ts
1852
+ var setsQueryKeys = {
1853
+ all: ["sets"],
1854
+ one: (params) => [...setsQueryKeys.all, params.setId]
1855
+ };
1856
+ var useSet = ({ setId, enabled }) => {
1857
+ return useQuery4({
1858
+ queryKey: setsQueryKeys.one({ setId }),
1859
+ queryFn: () => getSet({ setId }),
1860
+ enabled: setId !== void 0 && setId !== "" && enabled
1861
+ });
1862
+ };
1863
+ function getSetFromCache({
1864
+ setId,
1865
+ queryClient
1866
+ }) {
1867
+ if (!setId) return null;
1868
+ return queryClient.getQueryData(setsQueryKeys.one({ setId }));
1869
+ }
1870
+ function updateSetInCache({
1871
+ set,
1872
+ queryClient
1873
+ }) {
1874
+ const { id, ...setData } = set;
1875
+ queryClient.setQueryData(setsQueryKeys.one({ setId: id }), setData);
1876
+ }
1877
+
1878
+ // src/domains/sets/set.repo.ts
1879
+ var createSetRepo = () => {
1880
+ return {
1881
+ getSet
1882
+ };
1883
+ };
1884
+
1885
+ // src/constants/all-langs.json
1886
+ var all_langs_default = {
1887
+ af: "Afrikaans",
1888
+ sq: "Albanian",
1889
+ am: "Amharic",
1890
+ ar: "Arabic",
1891
+ hy: "Armenian",
1892
+ az: "Azerbaijani",
1893
+ eu: "Basque",
1894
+ be: "Belarusian",
1895
+ bn: "Bengali",
1896
+ bs: "Bosnian",
1897
+ bg: "Bulgarian",
1898
+ ca: "Catalan",
1899
+ ceb: "Cebuano",
1900
+ zh: "Chinese",
1901
+ co: "Corsican",
1902
+ hr: "Croatian",
1903
+ cs: "Czech",
1904
+ da: "Danish",
1905
+ nl: "Dutch",
1906
+ en: "English",
1907
+ eo: "Esperanto",
1908
+ et: "Estonian",
1909
+ fi: "Finnish",
1910
+ fr: "French",
1911
+ fy: "Frisian",
1912
+ gl: "Galician",
1913
+ ka: "Georgian",
1914
+ de: "German",
1915
+ el: "Greek",
1916
+ gu: "Gujarati",
1917
+ ht: "Haitian Creole",
1918
+ ha: "Hausa",
1919
+ haw: "Hawaiian",
1920
+ he: "Hebrew",
1921
+ hi: "Hindi",
1922
+ hmn: "Hmong",
1923
+ hu: "Hungarian",
1924
+ is: "Icelandic",
1925
+ ig: "Igbo",
1926
+ id: "Indonesian",
1927
+ ga: "Irish",
1928
+ it: "Italian",
1929
+ ja: "Japanese",
1930
+ jv: "Javanese",
1931
+ kn: "Kannada",
1932
+ kk: "Kazakh",
1933
+ km: "Khmer",
1934
+ ko: "Korean",
1935
+ ku: "Kurdish",
1936
+ ky: "Kyrgyz",
1937
+ lo: "Lao",
1938
+ la: "Latin",
1939
+ lv: "Latvian",
1940
+ lt: "Lithuanian",
1941
+ lb: "Luxembourgish",
1942
+ mk: "Macedonian",
1943
+ mg: "Malagasy",
1944
+ ms: "Malay",
1945
+ ml: "Malayalam",
1946
+ mt: "Maltese",
1947
+ mi: "Maori",
1948
+ mr: "Marathi",
1949
+ mn: "Mongolian",
1950
+ my: "Myanmar (Burmese)",
1951
+ ne: "Nepali",
1952
+ no: "Norwegian",
1953
+ ny: "Nyanja (Chichewa)",
1954
+ ps: "Pashto",
1955
+ fa: "Persian",
1956
+ pl: "Polish",
1957
+ pt: "Portuguese",
1958
+ pa: "Punjabi",
1959
+ ro: "Romanian",
1960
+ ru: "Russian",
1961
+ sm: "Samoan",
1962
+ gd: "Scots Gaelic",
1963
+ sr: "Serbian",
1964
+ st: "Sesotho",
1965
+ sn: "Shona",
1966
+ sd: "Sindhi",
1967
+ si: "Sinhala (Sinhalese)",
1968
+ sk: "Slovak",
1969
+ sl: "Slovenian",
1970
+ so: "Somali",
1971
+ es: "Spanish",
1972
+ su: "Sundanese",
1973
+ sw: "Swahili",
1974
+ sv: "Swedish",
1975
+ tl: "Tagalog (Filipino)",
1976
+ tg: "Tajik",
1977
+ ta: "Tamil",
1978
+ te: "Telugu",
1979
+ th: "Thai",
1980
+ tr: "Turkish",
1981
+ uk: "Ukrainian",
1982
+ ur: "Urdu",
1983
+ uz: "Uzbek",
1984
+ vi: "Vietnamese",
1985
+ cy: "Welsh",
1986
+ xh: "Xhosa",
1987
+ yi: "Yiddish",
1988
+ yo: "Yoruba",
1989
+ zu: "Zulu"
1990
+ };
1991
+
1992
+ // src/utils/ai/get-respond-card-tool.ts
1993
+ var getRespondCardTool = ({
1994
+ language,
1995
+ standard = "actfl"
1996
+ }) => {
1997
+ const lang = all_langs_default[language] || "English";
1998
+ const tool = {
1999
+ tool_choice: {
2000
+ type: "function",
2001
+ function: { name: "get_feedback" }
2002
+ },
2003
+ tools: [
2004
+ {
2005
+ type: "function",
2006
+ function: {
2007
+ name: "get_feedback",
2008
+ description: "Get feedback on a student's response",
2009
+ parameters: {
2010
+ type: "object",
2011
+ required: [
2012
+ "success",
2013
+ "score",
2014
+ "score_justification",
2015
+ "errors",
2016
+ "improvedResponse",
2017
+ "compliments"
2018
+ ],
2019
+ properties: {
2020
+ success: {
2021
+ type: "boolean",
2022
+ 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."
2023
+ },
2024
+ errors: {
2025
+ type: "array",
2026
+ items: {
2027
+ type: "object",
2028
+ required: ["error", "grammar_error_type", "correction", "justification"],
2029
+ properties: {
2030
+ error: {
2031
+ type: "string",
2032
+ description: "The grammatical error in the student's response."
2033
+ },
2034
+ correction: {
2035
+ type: "string",
2036
+ description: "The suggested correction to the error"
2037
+ },
2038
+ justification: {
2039
+ type: "string",
2040
+ description: `An explanation of the rationale behind the suggested correction. WRITE THIS IN ${lang}!`
2041
+ },
2042
+ grammar_error_type: {
2043
+ type: "string",
2044
+ enum: [
2045
+ "subjVerbAgree",
2046
+ "tenseErrors",
2047
+ "articleMisuse",
2048
+ "prepositionErrors",
2049
+ "adjNounAgree",
2050
+ "pronounErrors",
2051
+ "wordOrder",
2052
+ "verbConjugation",
2053
+ "pluralization",
2054
+ "negationErrors",
2055
+ "modalVerbMisuse",
2056
+ "relativeClause",
2057
+ "auxiliaryVerb",
2058
+ "complexSentenceAgreement",
2059
+ "idiomaticExpression",
2060
+ "registerInconsistency",
2061
+ "voiceMisuse"
2062
+ ],
2063
+ 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"
2064
+ }
2065
+ }
2066
+ },
2067
+ 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."
2068
+ },
2069
+ compliments: {
2070
+ type: "array",
2071
+ items: {
2072
+ type: "string"
2073
+ },
2074
+ description: `An array of strings, each representing something the student did well. Each string should be WRITTEN IN ${lang}!`
2075
+ },
2076
+ improvedResponse: {
2077
+ type: "string",
2078
+ description: "An improved response with proper grammar and more detail, if applicable."
2079
+ },
2080
+ score: {
2081
+ type: "number",
2082
+ description: "A score between 0 and 100, reflecting the overall quality of the response"
2083
+ },
2084
+ score_justification: {
2085
+ type: "string",
2086
+ description: "An explanation of the rationale behind the assigned score, considering both accuracy and fluency"
2087
+ }
2088
+ }
2089
+ }
2090
+ }
2091
+ }
2092
+ ]
2093
+ };
2094
+ if (standard === "wida") {
2095
+ const wida_level = {
2096
+ type: "number",
2097
+ enum: [1, 2, 3, 4, 5, 6],
2098
+ 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
2099
+
2100
+ 1 - Entering
2101
+ 2 - Emerging
2102
+ 3 - Developing
2103
+ 4 - Expanding
2104
+ 5 - Bridging
2105
+ 6 - Reaching
2106
+
2107
+ 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.
2108
+ `
2109
+ };
2110
+ const wida_justification = {
2111
+ type: "string",
2112
+ description: `An explanation of the rationale behind the assigned WIDA level of the response, considering both accuracy and fluency. WRITE THIS IN ENGLISH!`
2113
+ };
2114
+ tool.tools[0].function.parameters.required.push("wida_level");
2115
+ tool.tools[0].function.parameters.required.push("wida_justification");
2116
+ tool.tools[0].function.parameters.properties.wida_level = wida_level;
2117
+ tool.tools[0].function.parameters.properties.wida_justification = wida_justification;
2118
+ } else {
2119
+ const actfl_level = {
2120
+ type: "string",
2121
+ enum: ["NL", "NM", "NH", "IL", "IM", "IH", "AL", "AM", "AH", "S", "D"],
2122
+ 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"
2123
+ };
2124
+ const actfl_justification = {
2125
+ type: "string",
2126
+ description: "An explanation of the rationale behind the assigned ACTFL level, considering both accuracy and fluency"
2127
+ };
2128
+ tool.tools[0].function.parameters.required.push("actfl_level");
2129
+ tool.tools[0].function.parameters.required.push("actfl_justification");
2130
+ tool.tools[0].function.parameters.properties.actfl_level = actfl_level;
2131
+ tool.tools[0].function.parameters.properties.actfl_justification = actfl_justification;
2132
+ }
2133
+ return tool;
2134
+ };
2135
+
2136
2136
  // src/hooks/useActivity.ts
2137
2137
  import { useEffect as useEffect2 } from "react";
2138
2138
 
@@ -3027,6 +3027,7 @@ export {
3027
3027
  purify,
3028
3028
  refsCardsFiresotre,
3029
3029
  refsSetsFirestore,
3030
+ scoreQueryKeys,
3030
3031
  setsQueryKeys,
3031
3032
  updateCardInCache,
3032
3033
  updateSetInCache,
@@ -3035,13 +3036,19 @@ export {
3035
3036
  useAssignment,
3036
3037
  useBaseOpenAI,
3037
3038
  useCards,
3039
+ useClearScore,
3038
3040
  useCreateCard,
3039
3041
  useCreateCards,
3040
3042
  useCreateNotification,
3041
3043
  useGetCard,
3042
3044
  useOrganizationAccess,
3045
+ useScore,
3043
3046
  useSet,
3044
3047
  useSpeakableApi,
3048
+ useSubmitAssignmentScore,
3049
+ useSubmitPracticeScore,
3050
+ useUpdateCardScore,
3051
+ useUpdateScore,
3045
3052
  useUserCredits
3046
3053
  };
3047
3054
  //# sourceMappingURL=index.native.mjs.map