SarahXia0405 commited on
Commit
0101184
·
verified ·
1 Parent(s): 022a410

Update web/src/App.tsx

Browse files
Files changed (1) hide show
  1. web/src/App.tsx +175 -39
web/src/App.tsx CHANGED
@@ -14,7 +14,7 @@ import { toast } from "sonner";
14
  import { LeftSidebar } from "./components/sidebar/LeftSidebar";
15
 
16
  // backend API bindings
17
- import { apiChat, apiUpload, apiMemoryline } from "./lib/api";
18
 
19
  // NEW: review-star logic
20
  import {
@@ -645,35 +645,70 @@ function App() {
645
  else if (chatMode === "review") setReviewMessages((prev) => [...prev, userMessage]);
646
  else setQuizMessages((prev) => [...prev, userMessage]);
647
 
 
648
  if (chatMode === "quiz") {
649
- if (quizState.waitingForAnswer) {
650
- const isCorrect = Math.random() > 0.3;
651
- setIsTyping(true);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
652
 
 
 
653
  setTimeout(() => {
654
- const feedback = isCorrect ? "✅ Correct! Great job!" : "❌ Not quite right, but good effort!";
655
- const explanation =
656
- "Here's the explanation: The correct answer demonstrates understanding of the key concepts. Let me break it down for you...";
657
-
658
- const assistantMessage: Message = {
659
- id: (Date.now() + 1).toString(),
660
- role: "assistant",
661
- content: `${feedback}\n\n${explanation}`,
662
- timestamp: new Date(),
663
- sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
664
- showNextButton: true,
665
- };
666
-
667
- setIsTyping(false);
668
- setTimeout(() => {
669
- setQuizMessages((prev) => [...prev, assistantMessage]);
670
- setQuizState((prev) => ({ ...prev, waitingForAnswer: false, showNextButton: true }));
671
- }, 50);
672
- }, 2000);
673
  }
 
674
  return;
675
  }
676
 
 
677
  setIsTyping(true);
678
  try {
679
  const docType = getCurrentDocTypeForChat();
@@ -736,27 +771,60 @@ function App() {
736
  }
737
  };
738
 
739
- const handleNextQuestion = () => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
740
  setIsTyping(true);
741
- const question = generateQuizQuestion();
742
- let questionText = question.question;
743
-
744
- if (question.type === "multiple-choice") {
745
- questionText += "\n\n" + (question.options || []).join("\n");
746
- }
747
-
748
- setTimeout(() => {
 
 
 
 
 
 
 
 
 
 
 
 
749
  const assistantMessage: Message = {
750
- id: Date.now().toString(),
751
  role: "assistant",
752
- content: questionText,
753
  timestamp: new Date(),
 
754
  sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
755
- questionData: question,
756
  };
757
-
758
  setIsTyping(false);
759
-
760
  setTimeout(() => {
761
  setQuizMessages((prev) => [...prev, assistantMessage]);
762
  setQuizState((prev) => ({
@@ -766,10 +834,78 @@ function App() {
766
  showNextButton: false,
767
  }));
768
  }, 50);
769
- }, 2000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
770
  };
771
 
772
- const handleStartQuiz = () => handleNextQuestion();
773
 
774
  // =========================
775
  // ✅ File Upload (FIXED)
 
14
  import { LeftSidebar } from "./components/sidebar/LeftSidebar";
15
 
16
  // backend API bindings
17
+ import { apiChat, apiUpload, apiMemoryline, apiQuizStart } from "./lib/api";
18
 
19
  // NEW: review-star logic
20
  import {
 
645
  else if (chatMode === "review") setReviewMessages((prev) => [...prev, userMessage]);
646
  else setQuizMessages((prev) => [...prev, userMessage]);
647
 
648
+
649
  if (chatMode === "quiz") {
650
+ // Quiz mode: always route to backend (grading + next question handled server-side)
651
+ setIsTyping(true);
652
+
653
+ try {
654
+ const docType = getCurrentDocTypeForChat();
655
+
656
+ const r = await apiChat({
657
+ user_id: user.email,
658
+ message: content,
659
+ learning_mode: "quiz",
660
+ language_preference: mapLanguagePref(language),
661
+ doc_type: docType,
662
+ });
663
+
664
+ const refs = (r.refs || [])
665
+ .map((x) => {
666
+ const a = x?.source_file ? String(x.source_file) : "";
667
+ const b = x?.section ? String(x.section) : "";
668
+ const s = `${a}${a && b ? " — " : ""}${b}`.trim();
669
+ return s || null;
670
+ })
671
+ .filter(Boolean) as string[];
672
+
673
+ const assistantMessage: Message = {
674
+ id: (Date.now() + 1).toString(),
675
+ role: "assistant",
676
+ content: r.reply || "",
677
+ timestamp: new Date(),
678
+ references: refs.length ? refs : undefined,
679
+ sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
680
+ // Quiz flow is driven by backend, so don't force a local "Next" unless you want it
681
+ showNextButton: false,
682
+ };
683
 
684
+ setIsTyping(false);
685
+
686
  setTimeout(() => {
687
+ setQuizMessages((prev) => [...prev, assistantMessage]);
688
+ // In quiz, backend typically asks the next prompt; keep waitingForAnswer true
689
+ setQuizState((prev) => ({ ...prev, waitingForAnswer: true, showNextButton: false }));
690
+ }, 50);
691
+ } catch (e: any) {
692
+ setIsTyping(false);
693
+ toast.error(e?.message || "Quiz failed");
694
+
695
+ const assistantMessage: Message = {
696
+ id: (Date.now() + 1).toString(),
697
+ role: "assistant",
698
+ content: "Sorry — quiz request failed. Please try again.",
699
+ timestamp: new Date(),
700
+ sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
701
+ };
702
+
703
+ setTimeout(() => {
704
+ setQuizMessages((prev) => [...prev, assistantMessage]);
705
+ }, 50);
706
  }
707
+
708
  return;
709
  }
710
 
711
+
712
  setIsTyping(true);
713
  try {
714
  const docType = getCurrentDocTypeForChat();
 
771
  }
772
  };
773
 
774
+ const handleNextQuestion = async () => {
775
+ if (!user) return;
776
+
777
+ const prompt = "Please give me another question of the same quiz style.";
778
+ const sender: GroupMember = {
779
+ id: user.email,
780
+ name: user.name,
781
+ email: user.email,
782
+ avatar: `https://api.dicebear.com/7.x/avataaars/svg?seed=${encodeURIComponent(user.email)}`,
783
+ };
784
+
785
+ // record the "next" action as a user turn (keeps server history consistent)
786
+ const userMessage: Message = {
787
+ id: Date.now().toString(),
788
+ role: "user",
789
+ content: prompt,
790
+ timestamp: new Date(),
791
+ sender,
792
+ };
793
+
794
+ setQuizMessages((prev) => [...prev, userMessage]);
795
  setIsTyping(true);
796
+
797
+ try {
798
+ const docType = getCurrentDocTypeForChat();
799
+ const r = await apiChat({
800
+ user_id: user.email,
801
+ message: prompt,
802
+ learning_mode: "quiz",
803
+ language_preference: mapLanguagePref(language),
804
+ doc_type: docType,
805
+ });
806
+
807
+ const refs = (r.refs || [])
808
+ .map((x) => {
809
+ const a = x?.source_file ? String(x.source_file) : "";
810
+ const b = x?.section ? String(x.section) : "";
811
+ const s = `${a}${a && b ? " — " : ""}${b}`.trim();
812
+ return s || null;
813
+ })
814
+ .filter(Boolean) as string[];
815
+
816
  const assistantMessage: Message = {
817
+ id: (Date.now() + 1).toString(),
818
  role: "assistant",
819
+ content: r.reply || "",
820
  timestamp: new Date(),
821
+ references: refs.length ? refs : undefined,
822
  sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
823
+ showNextButton: false,
824
  };
825
+
826
  setIsTyping(false);
827
+
828
  setTimeout(() => {
829
  setQuizMessages((prev) => [...prev, assistantMessage]);
830
  setQuizState((prev) => ({
 
834
  showNextButton: false,
835
  }));
836
  }, 50);
837
+ } catch (e: any) {
838
+ setIsTyping(false);
839
+ toast.error(e?.message || "Quiz failed");
840
+
841
+ const assistantMessage: Message = {
842
+ id: (Date.now() + 1).toString(),
843
+ role: "assistant",
844
+ content: "Sorry — quiz request failed. Please try again.",
845
+ timestamp: new Date(),
846
+ sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
847
+ };
848
+
849
+ setTimeout(() => setQuizMessages((prev) => [...prev, assistantMessage]), 50);
850
+ }
851
+ };
852
+
853
+ const handleStartQuiz = async () => {
854
+ if (!user) return;
855
+
856
+ setIsTyping(true);
857
+ try {
858
+ const docType = getCurrentDocTypeForChat();
859
+
860
+ const r = await apiQuizStart({
861
+ user_id: user.email,
862
+ language_preference: mapLanguagePref(language),
863
+ doc_type: docType,
864
+ learning_mode: "quiz",
865
+ });
866
+
867
+ const refs = (r.refs || [])
868
+ .map((x) => {
869
+ const a = x?.source_file ? String(x.source_file) : "";
870
+ const b = x?.section ? String(x.section) : "";
871
+ const s = `${a}${a && b ? " — " : ""}${b}`.trim();
872
+ return s || null;
873
+ })
874
+ .filter(Boolean) as string[];
875
+
876
+ const assistantMessage: Message = {
877
+ id: Date.now().toString(),
878
+ role: "assistant",
879
+ content: r.reply || "",
880
+ timestamp: new Date(),
881
+ references: refs.length ? refs : undefined,
882
+ sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
883
+ showNextButton: false,
884
+ };
885
+
886
+ setIsTyping(false);
887
+
888
+ setTimeout(() => {
889
+ setQuizMessages((prev) => [...prev, assistantMessage]);
890
+ // backend will ask: "choose 1 or 2" first; user should answer next
891
+ setQuizState({ currentQuestion: 0, waitingForAnswer: true, showNextButton: false });
892
+ }, 50);
893
+ } catch (e: any) {
894
+ setIsTyping(false);
895
+ toast.error(e?.message || "Start quiz failed");
896
+
897
+ const assistantMessage: Message = {
898
+ id: Date.now().toString(),
899
+ role: "assistant",
900
+ content: "Sorry — could not start the quiz. Please try again.",
901
+ timestamp: new Date(),
902
+ sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
903
+ };
904
+
905
+ setTimeout(() => setQuizMessages((prev) => [...prev, assistantMessage]), 50);
906
+ }
907
  };
908
 
 
909
 
910
  // =========================
911
  // ✅ File Upload (FIXED)