From 7594f649890d27d558be35c9d40a0aa8211aec67 Mon Sep 17 00:00:00 2001
From: alyssaf16 <alyssa_feinberg@brown.edu>
Date: Thu, 6 Jun 2024 22:20:24 -0400
Subject: Flashcard changes - menu added

---
 src/client/views/nodes/ComparisonBox.tsx | 99 +++++++++++++++++++++++++-------
 1 file changed, 79 insertions(+), 20 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 6d4af2f3e..f844892c5 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -1,9 +1,9 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@mui/material';
-import { action, computed, makeObservable, observable } from 'mobx';
+import { action, computed, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { returnFalse, returnNone, setupMoveUpEvents } from '../../../ClientUtils';
+import { returnFalse, returnNone, returnTrue, setupMoveUpEvents } from '../../../ClientUtils';
 import { emptyFunction } from '../../../Utils';
 import { Doc, Opt } from '../../../fields/Doc';
 import { DocData } from '../../../fields/DocSymbols';
@@ -27,6 +27,7 @@ import { FormattedTextBox } from './formattedText/FormattedTextBox';
 import ReactLoading from 'react-loading';
 import { ContextMenu } from '../ContextMenu';
 import { ContextMenuProps } from '../ContextMenuItem';
+import { tickStep } from 'd3';
 
 @observer
 export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@@ -37,7 +38,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
     constructor(props: FieldViewProps) {
         super(props);
         makeObservable(this);
-        // this._isAnyChildContentActive = true;
     }
 
     @observable private _inputValue = '';
@@ -63,12 +63,19 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
     @computed get clipHeight() {
         return NumCast(this.layoutDoc[this.clipHeightKey], 200);
     }
+    get revealOp() {
+        return this.layoutDoc[`_${this._props.fieldKey}_revealOp`];
+    }
     get clipHeightKey() {
         return '_' + this._props.fieldKey + '_clipHeight';
     }
 
     componentDidMount() {
         this._props.setContentViewBox?.(this);
+        reaction(
+            () => this._props.isSelected(),
+            selected => !selected && (this.childActive = false)
+        );
     }
     protected createDropTarget = (ele: HTMLDivElement | null, fieldKey: string, disposerId: number) => {
         this._disposers[disposerId]?.();
@@ -98,7 +105,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                 emptyFunction,
                 action((moveEv, doubleTap) => {
                     if (doubleTap) {
-                        this._isAnyChildContentActive = true;
+                        this.childActive = true;
                         if (!this.dataDoc[this.fieldKey + '_1'] && !this.dataDoc[this.fieldKey]) this.dataDoc[this.fieldKey + '_1'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc);
                         if (!this.dataDoc[this.fieldKey + '_2'] && !this.dataDoc[this.fieldKey + '_alternate']) this.dataDoc[this.fieldKey + '_2'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc);
                     }
@@ -106,7 +113,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                 false,
                 undefined,
                 action(() => {
-                    if (this._isAnyChildContentActive) return;
+                    if (this.childActive) return;
                     this._animating = 'all 200ms';
                     // on click, animate slider movement to the targetWidth
                     this.layoutDoc[this.clipWidthKey] = (targetWidth * 100) / this._props.PanelWidth();
@@ -247,7 +254,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
     hoverFlip = (side: string | undefined) => {
         if (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] === 'hover') this.layoutDoc[`_${this._props.fieldKey}_usePath`] = side;
     };
-
     /**
      * Creates the button used to flip the flashcards.
      */
@@ -259,7 +265,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                     className="formattedTextBox-alternateButton"
                     onPointerDown={e =>
                         setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, () => {
-                            console.log(this.layoutDoc[`_${this._props.fieldKey}_revealOp`]);
                             if (!this.layoutDoc[`_${this._props.fieldKey}_revealOp`] || this.layoutDoc[`_${this._props.fieldKey}_revealOp`] === 'flip') {
                                 this.flipFlashcard();
 
@@ -271,6 +276,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                     style={{
                         background: usepath === 'alternate' ? 'white' : 'black',
                         color: usepath === 'alternate' ? 'black' : 'white',
+                        display: 'inline-block',
                     }}>
                     <div key="alternate" className="formattedTextBox-flip">
                         <FontAwesomeIcon icon="turn-up" size="1x" />
@@ -280,6 +286,37 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
         );
     }
 
+    @computed get flashcardMenu() {
+        return (
+            <div>
+                <Tooltip
+                    title={
+                        this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? (
+                            <div className="dash-tooltip">Flip to front side to use GPT</div>
+                        ) : (
+                            <div className="dash-tooltip">Ask GPT to create an answer on the back side of the flashcard</div>
+                        )
+                    }>
+                    <div style={{ position: 'absolute', bottom: '3px', right: '55px', cursor: 'pointer' }} onPointerDown={e => (!this.layoutDoc[`_${this._props.fieldKey}_usePath`] ? this.askGPT(GPTCallType.CHATCARD) : null)}>
+                        <FontAwesomeIcon icon="lightbulb" size="xl" />
+                    </div>
+                </Tooltip>
+                <Tooltip title={<div className="dash-tooltip">Hover to reveal</div>}>
+                    <div
+                        style={{ position: 'absolute', bottom: '3px', right: '25px', cursor: 'pointer' }}
+                        onClick={e => (this.revealOp === 'hover' ? (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'flip') : (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'hover'))}>
+                        <FontAwesomeIcon color={this.revealOp === 'hover' ? 'blue' : 'black'} icon="layer-group" size="xl" />
+                    </div>
+                </Tooltip>
+                {this.overlayAlternateIcon}
+            </div>
+        );
+    }
+
+    @action activateContent = () => {
+        this.childActive = true;
+    };
+
     @action handleRenderGPTClick = () => {
         // Call the GPT model and get the output
         this.layoutDoc[`_${this._props.fieldKey}_usePath`] = 'alternate';
@@ -320,8 +357,12 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
         const rubricText = ' Rubric: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text);
         const queryText = questionText + ' UserAnswer: ' + this._inputValue + '. ' + rubricText;
         this._loading = true;
+        const doc = DocCast(this.dataDoc[this.props.fieldKey + '_0']);
         if (callType == GPTCallType.CHATCARD) {
-            DocCast(this.dataDoc[this.props.fieldKey + '_0'])[DocData].text = '';
+            if (StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text) === '') {
+                this._loading = false;
+                return;
+            }
             this.flipFlashcard();
         }
         try {
@@ -330,7 +371,13 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                 console.error('GPT call failed');
                 return;
             }
-            this.animateRes(0, res, callType);
+            // this.animateRes(0, res, callType);
+            if (callType == GPTCallType.CHATCARD) {
+                DocCast(this.dataDoc[this.props.fieldKey + '_0'])[DocData].text = res;
+                // this.flipFlashcard();
+            }
+            if (callType == GPTCallType.QUIZ) this._outputValue = res;
+            // DocCast(this.dataDoc[this.props.fieldKey + '_0'])[DocData].text = res;
             // this._outputValue = res;
             console.log(res);
         } catch (err) {
@@ -341,10 +388,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' });
-    };
+    // specificMenu = (): void => {
+    //     const cm = ContextMenu.Instance;
+    //     cm.addItem({ description: 'Create an Answer on the Back', event: () => this.askGPT(GPTCallType.CHATCARD), icon: 'pencil' });
+    // };
+    @observable childActive = false;
 
     render() {
         const clearButton = (which: string) => (
@@ -378,12 +426,13 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                         removeDocument={whichSlot.endsWith('1') ? this.remDoc1 : this.remDoc2}
                         NativeWidth={this.layoutWidth}
                         NativeHeight={this.layoutHeight}
-                        isContentActive={emptyFunction}
+                        isContentActive={() => this.childActive}
                         isDocumentActive={returnFalse}
+                        dontSelect={returnTrue}
                         whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
-                        styleProvider={this._isAnyChildContentActive ? this._props.styleProvider : this.docStyleProvider}
+                        styleProvider={this.childActive ? this._props.styleProvider : this.docStyleProvider}
                         hideLinkButton
-                        pointerEvents={this._isAnyChildContentActive ? undefined : returnNone}
+                        pointerEvents={this.childActive ? undefined : returnNone}
                     />
                     <div style={{ position: 'absolute', top: '-5px', left: '2px' }}>{layoutString ? null : clearButton(whichSlot)}</div>
                 </> // placeholder image if doc is missingleft: `${NumCast(this.layoutDoc.width, 200) - 33}px`
@@ -394,7 +443,15 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
             );
         };
         const displayBox = (which: string, index: number, cover: number) => (
-            <div className={`${index === 0 ? 'before' : 'after'}Box-cont`} key={which} style={{ width: this._props.PanelWidth() }} onPointerDown={e => this.registerSliding(e, cover)} ref={ele => this.createDropTarget(ele, which, index)}>
+            <div
+                className={`${index === 0 ? 'before' : 'after'}Box-cont`}
+                key={which}
+                style={{ width: this._props.PanelWidth() }}
+                onPointerDown={e => {
+                    this.registerSliding(e, cover);
+                    this.activateContent();
+                }}
+                ref={ele => this.createDropTarget(ele, which, index)}>
                 {displayDoc(which)}
             </div>
         );
@@ -431,6 +488,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                             <textarea
                                 value={this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? this._outputValue : this._inputValue}
                                 onChange={this.handleInputChange}
+                                onScroll={e => e.stopPropagation()}
                                 readOnly={this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate'}></textarea>
 
                             {this._loading ? (
@@ -457,7 +515,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}
+                    // onContextMenu={this.specificMenu}
                     style={{ display: 'flex', flexDirection: 'column' }}
                     onMouseEnter={() => {
                         this.hoverFlip('alternate');
@@ -473,7 +531,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                             <ReactLoading type="spin" height={30} width={30} color={'blue'} />
                         </div>
                     ) : null}
-                    {this.overlayAlternateIcon}
+                    {this.flashcardMenu}
+                    {/* {this.overlayAlternateIcon} */}
                 </div>
             );
         }
@@ -491,7 +550,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                         left: `calc(${this.clipWidth + '%'} - 0.5px)`,
                         cursor: this.clipWidth < 5 ? 'e-resize' : this.clipWidth / 100 > (this._props.PanelWidth() - 5) / this._props.PanelWidth() ? 'w-resize' : undefined,
                     }}
-                    onPointerDown={e => !this._isAnyChildContentActive && this.registerSliding(e, this._props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */
+                    onPointerDown={e => !this.childActive && this.registerSliding(e, this._props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */
                 >
                     <div className="slide-handle" />
                 </div>
-- 
cgit v1.2.3-70-g09d2

