From c76505f56a83625e3993427838aaee0c54c5fb81 Mon Sep 17 00:00:00 2001
From: alyssaf16 <alyssa_feinberg@brown.edu>
Date: Thu, 6 Jun 2024 09:53:12 -0400
Subject: Fixes to chatcard and quizcard

---
 src/client/views/nodes/ComparisonBox.tsx | 43 ++++++++++++++++++++++++++------
 1 file changed, 35 insertions(+), 8 deletions(-)

(limited to 'src/client/views/nodes/ComparisonBox.tsx')

diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index c0c173d9a..6d4af2f3e 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -25,6 +25,8 @@ import { DocumentView } from './DocumentView';
 import { FieldView, FieldViewProps } from './FieldView';
 import { FormattedTextBox } from './formattedText/FormattedTextBox';
 import ReactLoading from 'react-loading';
+import { ContextMenu } from '../ContextMenu';
+import { ContextMenuProps } from '../ContextMenuItem';
 
 @observer
 export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@@ -282,7 +284,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
         // Call the GPT model and get the output
         this.layoutDoc[`_${this._props.fieldKey}_usePath`] = 'alternate';
         this._outputValue = '';
-        if (this._inputValue) this.askGPT();
+        if (this._inputValue) this.askGPT(GPTCallType.QUIZ);
     };
 
     @action handleRenderClick = () => {
@@ -290,12 +292,22 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
         this.layoutDoc[`_${this._props.fieldKey}_usePath`] = undefined;
     };
 
-    animateRes = (resIndex: number, newText: string) => {
+    animateRes = (resIndex: number, newText: string, callType: GPTCallType) => {
         if (resIndex < newText.length) {
             // const marks = this._editorView?.state.storedMarks ?? [];
-            this._outputValue += newText[resIndex];
+            switch (callType) {
+                case GPTCallType.CHATCARD:
+                    DocCast(this.dataDoc[this.props.fieldKey + '_0'])[DocData].text += newText[resIndex];
+                    break;
+                case GPTCallType.QUIZ:
+                    this._outputValue += newText[resIndex];
+                    break;
+                default:
+                    return;
+            }
+
             // this._editorView?.dispatch(this._editorView?.state.tr.insertText(newText[resIndex]).setStoredMarks(this._outputValue));
-            setTimeout(() => this.animateRes(resIndex + 1, newText), 20);
+            setTimeout(() => this.animateRes(resIndex + 1, newText, callType), 20);
         }
     };
 
@@ -303,18 +315,22 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
      * Calls the GPT model to create QuizCards. Evaluates how similar the user's response is to the alternate
      * side of the flashcard.
      */
-    askGPT = async (): Promise<string | undefined> => {
+    askGPT = async (callType: GPTCallType): Promise<string | undefined> => {
         const questionText = 'Question: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text);
         const rubricText = ' Rubric: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text);
         const queryText = questionText + ' UserAnswer: ' + this._inputValue + '. ' + rubricText;
         this._loading = true;
+        if (callType == GPTCallType.CHATCARD) {
+            DocCast(this.dataDoc[this.props.fieldKey + '_0'])[DocData].text = '';
+            this.flipFlashcard();
+        }
         try {
-            const res = await gptAPICall(queryText, GPTCallType.QUIZ);
+            const res = await gptAPICall(callType == GPTCallType.QUIZ ? queryText : questionText, callType);
             if (!res) {
                 console.error('GPT call failed');
                 return;
             }
-            this.animateRes(0, '\n\n' + res);
+            this.animateRes(0, res, callType);
             // this._outputValue = res;
             console.log(res);
         } catch (err) {
@@ -325,6 +341,11 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
     layoutWidth = () => NumCast(this.layoutDoc.width, 200);
     layoutHeight = () => NumCast(this.layoutDoc.height, 200);
 
+    specificMenu = (): void => {
+        const cm = ContextMenu.Instance;
+        cm.addItem({ description: 'Create an Answer on the Back', event: () => this.askGPT(GPTCallType.CHATCARD), icon: 'pencil' });
+    };
+
     render() {
         const clearButton = (which: string) => (
             <Tooltip title={<div className="dash-tooltip">remove</div>}>
@@ -425,7 +446,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                         </div>
                         <div className="submit-button" style={{ overflow: 'hidden', marginBottom: '2px', display: this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? 'flex' : 'none' }}>
                             <button type="button" onClick={this.handleRenderClick} style={{ borderRadius: '2px' }}>
-                                Try Again
+                                Redo the Question
                             </button>
                         </div>
                     </div>
@@ -436,6 +457,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
             return (
                 <div
                     className={`comparisonBox${this._props.isContentActive() ? '-interactive' : ''}`} /* change className to easily disable/enable pointer events in CSS */
+                    onContextMenu={this.specificMenu}
                     style={{ display: 'flex', flexDirection: 'column' }}
                     onMouseEnter={() => {
                         this.hoverFlip('alternate');
@@ -446,6 +468,11 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                     // onPointerUp={() => (this._isAnyChildContentActive = true)}
                 >
                     {displayBox(`${this.fieldKey}_${side === 0 ? 1 : 0}`, side, this._props.PanelWidth() - 3)}
+                    {this._loading ? (
+                        <div className="loading-spinner" style={{ position: 'absolute' }}>
+                            <ReactLoading type="spin" height={30} width={30} color={'blue'} />
+                        </div>
+                    ) : null}
                     {this.overlayAlternateIcon}
                 </div>
             );
-- 
cgit v1.2.3-70-g09d2

