aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/CollectionCarouselView.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections/CollectionCarouselView.tsx')
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx241
1 files changed, 189 insertions, 52 deletions
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 4bec2d963..ba7c944a0 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -1,6 +1,7 @@
/* eslint-disable react/jsx-props-no-spreading */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { computed, makeObservable } from 'mobx';
+import { Tooltip } from '@mui/material';
+import { action, computed, makeObservable, observable, trace } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { StopEvent, returnFalse, returnOne, returnTrue, returnZero } from '../../../ClientUtils';
@@ -8,8 +9,8 @@ import { emptyFunction } from '../../../Utils';
import { Doc, Opt } from '../../../fields/Doc';
import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { DocumentType } from '../../documents/DocumentTypes';
+import { Docs } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
-import { ContextMenu } from '../ContextMenu';
import { StyleProp } from '../StyleProp';
import { DocumentView } from '../nodes/DocumentView';
import { FieldViewProps } from '../nodes/FieldView';
@@ -18,9 +19,15 @@ import './CollectionCarouselView.scss';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
enum cardMode {
- PRACTICE = 'practice',
+ // PRACTICE = 'practice',
STAR = 'star',
+ // QUIZ = 'quiz',
+ ALL = 'all',
+}
+enum practiceMode {
+ PRACTICE = 'practice',
QUIZ = 'quiz',
+ NORMAL = 'normal',
}
enum practiceVal {
MISSED = 'missed',
@@ -29,12 +36,22 @@ enum practiceVal {
@observer
export class CollectionCarouselView extends CollectionSubView() {
private _dropDisposer?: DragManager.DragDropDisposer;
+ @observable private _practiceMessage: string | undefined;
+ @observable private _filterMessage: string | undefined;
get practiceField() { return this.fieldKey + "_practice"; } // prettier-ignore
- get starField() { return this.fieldKey + "_star"; } // prettier-ignore
+ get sideField() { return "_" + this.fieldKey + "_usePath"; } // prettier-ignore
+ get starField() { return "star"; } // prettier-ignore
constructor(props: SubCollectionViewProps) {
super(props);
makeObservable(this);
+ // this.setModes();
+ this.layoutDoc.filterOp = cardMode.ALL;
+ Doc.setDocFilter(this.Document, 'star', undefined, 'match');
+ this.layoutDoc.practiceMode = practiceMode.NORMAL;
+ this.layoutDoc._carousel_index = 0;
+ this.carouselItems.forEach(item => { item.layout[this.practiceField] = undefined}); //prettier-ignore
+ console.log(this.carouselItems.length);
}
componentWillUnmount() {
@@ -49,16 +66,33 @@ export class CollectionCarouselView extends CollectionSubView() {
};
@computed get carouselItems() {
+ this.childLayoutPairs.map(pair => {
+ pair.layout.embedContainer = this.Document;
+ });
return this.childLayoutPairs.filter(pair => pair.layout.type !== DocumentType.LINK);
}
@computed get marginX() {
return NumCast(this.layoutDoc.caption_xMargin, 50);
}
+ @action setPracticeMessage = (mes: string | undefined) => {
+ this._practiceMessage = mes;
+ };
+ @action setFilterMessage = (mes: string | undefined) => {
+ this._filterMessage = mes;
+ };
+
+ setModes = () => {
+ this.layoutDoc.filterOp = cardMode.ALL;
+ Doc.setDocFilter(this.Document, 'data_star', undefined, 'match');
+ this.layoutDoc.practiceMode = practiceMode.NORMAL;
+ this.layoutDoc._carousel_index = 0;
+ };
+
move = (dir: number) => {
const moveToCardWithField = (match: (doc: Doc) => boolean): boolean => {
let startInd = (NumCast(this.layoutDoc._carousel_index) + dir) % this.carouselItems.length;
- while (!match(this.carouselItems?.[startInd].layout) && (startInd + dir + this.carouselItems.length) % this.carouselItems.length !== this.layoutDoc._carousel_index) {
+ while (!match(this.carouselItems?.[startInd].layout) && (startInd + this.carouselItems.length) % this.carouselItems.length !== this.layoutDoc._carousel_index) {
startInd = (startInd + dir + this.carouselItems.length) % this.carouselItems.length;
}
if (match(this.carouselItems?.[startInd].layout)) {
@@ -67,23 +101,28 @@ export class CollectionCarouselView extends CollectionSubView() {
}
return match(this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout);
};
- switch (StrCast(this.layoutDoc.filterOp)) {
- case cardMode.STAR: // go to a flashcard that is starred, skip the ones that aren't
+
+ switch (this.layoutDoc.practiceMode && this.layoutDoc.filterOp) {
+ case practiceMode.PRACTICE && cardMode.ALL:
+ if (!moveToCardWithField((doc: Doc) => doc[this.practiceField] !== practiceVal.CORRECT)) {
+ this._practiceMessage = 'Finished! Unselect practice mode to view all flashcards.';
+ this.carouselItems.forEach(item => { item.layout[this.practiceField] = undefined}); //prettier-ignore
+ }
+ break;
+ case !practiceMode.PRACTICE && cardMode.STAR:
if (!moveToCardWithField((doc: Doc) => !!doc[this.starField])) {
- this.layoutDoc.filterOp = undefined; // if there aren't any starred, show all cards
+ this._filterMessage = 'No starred items. Unselect this view to see all flashcards and star them.';
}
break;
- case cardMode.PRACTICE: // go to a new index that is missed, skip the ones that are correct
- if (!moveToCardWithField((doc: Doc) => doc[this.practiceField] !== practiceVal.CORRECT)) {
- this.layoutDoc.filterOp = undefined; // if all of the cards are correct, show all cards and exit practice mode
-
- this.carouselItems.forEach(item => { // reset all the practice values
- item.layout[this.practiceField] = undefined;
- });
+ case practiceMode.PRACTICE && cardMode.STAR:
+ if (!moveToCardWithField((doc: Doc) => doc[this.practiceField] !== practiceVal.CORRECT && doc[this.starField] === true)) {
+ this._filterMessage = 'No flashcards to show! Unselect mode to view all flashcards.';
+ this._practiceMessage = undefined;
}
break;
- default: moveToCardWithField(returnTrue);
- } // prettier-ignore
+ default:
+ moveToCardWithField(returnTrue);
+ }
};
/**
@@ -109,6 +148,8 @@ export class CollectionCarouselView extends CollectionSubView() {
e.stopPropagation();
const curDoc = this.carouselItems[NumCast(this.layoutDoc._carousel_index)];
curDoc.layout[this.starField] = curDoc.layout[this.starField] ? undefined : true;
+ // if (!curDoc.layout[this.starField]) this.move(1);
+ // this.layoutDoc._carousel_index = undefined;
};
/*
@@ -130,22 +171,43 @@ export class CollectionCarouselView extends CollectionSubView() {
onContentDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
onContentClick = () => ScriptCast(this.layoutDoc.onChildClick);
captionWidth = () => this._props.PanelWidth() - 2 * this.marginX;
- specificMenu = (): void => {
- const cm = ContextMenu.Instance;
-
- const revealOptions = cm.findByDescription('Filter Flashcards');
- const revealItems = revealOptions?.subitems ?? [];
- revealItems.push({description: 'All', event: () => {this.layoutDoc.filterOp = undefined;}, icon: 'layer-group',}); // prettier-ignore
- revealItems.push({description: 'Star', event: () => {this.layoutDoc.filterOp = cardMode.STAR;}, icon: 'star',}); // prettier-ignore
- revealItems.push({description: 'Practice Mode', event: () => {this.layoutDoc.filterOp = cardMode.PRACTICE;}, icon: 'check',}); // prettier-ignore
- revealItems.push({description: 'Quiz Cards', event: () => {this.layoutDoc.filterOp = cardMode.QUIZ;}, icon: 'pencil',}); // prettier-ignore
- !revealOptions && cm.addItem({ description: 'Filter Flashcards', addDivider: false, noexpand: true, subitems: revealItems, icon: 'layer-group' });
+
+ setPracticeMode = (mode: practiceMode) => {
+ this.layoutDoc.practiceMode = mode;
+ this.carouselItems?.map(doc => (doc.layout[this.practiceField] = undefined));
+ switch (mode) {
+ case practiceMode.QUIZ:
+ this.carouselItems?.map(doc => (doc.layout[this.sideField] = undefined));
+ break;
+ case practiceMode.NORMAL:
+ this.setPracticeMessage(undefined);
+ break;
+ }
};
+
+ setFilterMode = (mode: cardMode) => {
+ this.layoutDoc.filterOp = mode;
+ switch (mode) {
+ case cardMode.STAR:
+ // Doc.setDocFilter(this.Document, 'data_star', true, 'match');
+ this.move(1);
+ break;
+ default:
+ this.setFilterMessage(undefined); // prettier-ignore
+ // Doc.setDocFilter(this.Document, 'data_star', true, 'remove');
+ }
+ };
+
@computed get content() {
+ trace();
+ if (this.layoutDoc._carousel_index === this.carouselItems.length && this.layoutDoc._carousel_index !== 0) {
+ this.move(1);
+ }
const index = NumCast(this.layoutDoc._carousel_index);
const curDoc = this.carouselItems?.[index];
const captionProps = { ...this._props, NativeScaling: returnOne, PanelWidth: this.captionWidth, fieldKey: 'caption', setHeight: undefined, setContentView: undefined };
const carouselShowsCaptions = StrCast(this.layoutDoc._layout_showCaption);
+
return !(curDoc?.layout instanceof Doc) ? null : (
<>
<div className="collectionCarouselView-image" key="image">
@@ -155,10 +217,12 @@ export class CollectionCarouselView extends CollectionSubView() {
NativeHeight={returnZero}
fitWidth={undefined}
setContentViewBox={undefined}
+ childFilters={this.childDocFilters}
onDoubleClickScript={this.onContentDoubleClick}
onClickScript={this.onContentClick}
isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive}
isContentActive={(this._props.childContentsActive ?? this._props.isContentActive() === false) ? returnFalse : emptyFunction}
+ addDocument={this._props.addDocument}
hideCaptions={!!carouselShowsCaptions} // hide captions if the carousel is configured to show the captions
renderDepth={this._props.renderDepth + 1}
LayoutTemplate={this._props.childLayoutTemplate}
@@ -185,6 +249,25 @@ export class CollectionCarouselView extends CollectionSubView() {
</>
);
}
+
+ containsDifTypes = (): boolean => {
+ return this.carouselItems.filter(doc => !doc.layout._layout_isFlashcard).length !== 0;
+ };
+
+ addFlashcard() {
+ const newDoc = Docs.Create.ComparisonDocument('', { _layout_isFlashcard: true, _width: 300, _height: 300 });
+ this.addDocument?.(newDoc);
+ // DocUtils.copyDragFactory(newDoc);
+ // this._props.addDocument?.();
+ // newDoc.layout = this.layoutDoc;
+ // newDoc.data = this.dataDoc;
+ // Doc.AddDocToList()
+ // this._props.parent._props.addDocument();
+ // this.childLayoutPairs.push({ newDoc.layout, newDoc.data});
+ // this._props.addDocument?.(newDoc);
+ // console.log('HERE');
+ }
+
@computed get buttons() {
if (!this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)]) return null;
return (
@@ -195,54 +278,108 @@ export class CollectionCarouselView extends CollectionSubView() {
<div key="fwd" className="carouselView-fwd" onClick={this.advance}>
<FontAwesomeIcon icon="chevron-right" size="2x" />
</div>
- <div key="star" className="carouselView-star" onClick={this.star}>
- <FontAwesomeIcon icon="star" color={this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.starField] ? 'yellow' : 'gray'} size="1x" />
- </div>
- <div key="remove" className="carouselView-remove" onClick={e => this.setPracticeVal(e, practiceVal.MISSED)} style={{ visibility: this.layoutDoc.filterOp === cardMode.PRACTICE ? 'visible' : 'hidden' }}>
- <FontAwesomeIcon icon="xmark" color="red" size="1x" />
- </div>
- <div key="check" className="carouselView-check" onClick={e => this.setPracticeVal(e, practiceVal.CORRECT)} style={{ visibility: this.layoutDoc.filterOp === cardMode.PRACTICE ? 'visible' : 'hidden' }}>
- <FontAwesomeIcon icon="check" color="green" size="1x" />
- </div>
+ {!this.containsDifTypes() ? (
+ <div>
+ <Tooltip title="star">
+ <div key="star" className="carouselView-star" onClick={this.star}>
+ <FontAwesomeIcon icon="star" color={this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.starField] ? 'yellow' : 'gray'} size="1x" />
+ </div>
+ </Tooltip>
+ {/* <Tooltip title="add new flashcard to pile">
+ <div key="add" className="carouselView-add" onClick={this.addFlashcard}>
+ <FontAwesomeIcon icon="plus" color={this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.starField] ? 'yellow' : 'gray'} size="1x" />
+ </div>
+ </Tooltip> */}
+ </div>
+ ) : null}
+ {this.layoutDoc.practiceMode === practiceMode.PRACTICE ? (
+ <div>
+ <Tooltip title="Incorrect. View again later.">
+ <div key="remove" className="carouselView-remove" onClick={e => this.setPracticeVal(e, practiceVal.MISSED)}>
+ <FontAwesomeIcon icon="xmark" color="red" size="1x" />
+ </div>
+ </Tooltip>
+ <Tooltip title="Correct">
+ <div key="check" className="carouselView-check" onClick={e => this.setPracticeVal(e, practiceVal.CORRECT)}>
+ <FontAwesomeIcon icon="check" color="green" size="1x" />
+ </div>
+ </Tooltip>
+ </div>
+ ) : null}
</>
);
}
+ togglePracticeMode = (mode: practiceMode) => {
+ if (mode === this.layoutDoc.practiceMode) {
+ this.setPracticeMode(practiceMode.NORMAL);
+ // this.setPracticeMessage("undefined");
+ } else this.setPracticeMode(mode);
+ };
+ toggleFilterMode = () => { this.layoutDoc.filterOp === cardMode.STAR ? this.setFilterMode(cardMode.ALL) : this.setFilterMode(cardMode.STAR)}; //prettier-ignore
+ setColor = (mode: practiceMode | cardMode, which: string) => { return which === mode ? 'white' : 'light gray'}; //prettier-ignore
+
+ @computed get menu() {
+ return (
+ <div className="carouselView-menu">
+ <Tooltip title="Practice flashcards using GPT">
+ <div key="back" className="carouselView-quiz" onClick={e => this.togglePracticeMode(practiceMode.QUIZ)}>
+ <FontAwesomeIcon icon="file-pen" color={this.setColor(practiceMode.QUIZ, StrCast(this.layoutDoc.practiceMode))} size="1x" />
+ </div>
+ </Tooltip>
+ <Tooltip title={this.layoutDoc.practiceMode === practiceMode.PRACTICE ? 'Exit practice mode' : 'Practice flashcards manually'}>
+ <div key="back" className="carouselView-practice" onClick={e => this.togglePracticeMode(practiceMode.PRACTICE)}>
+ <FontAwesomeIcon icon="check" color={this.setColor(practiceMode.PRACTICE, StrCast(this.layoutDoc.practiceMode))} size="1x" />
+ </div>
+ </Tooltip>
+ <Tooltip title={this.layoutDoc.filterOp === cardMode.STAR ? 'Show all cards' : 'Show only starred cards'}>
+ <div key="back" className="carouselView-starFilter" onClick={e => this.toggleFilterMode()}>
+ <FontAwesomeIcon icon="filter" color={this.setColor(cardMode.STAR, StrCast(this.layoutDoc.filterOp))} size="1x" />
+ </div>
+ </Tooltip>
+ </div>
+ );
+ }
+
render() {
return (
<div
className="collectionCarouselView-outer"
ref={this.createDashEventsTarget}
- onContextMenu={this.specificMenu}
style={{
background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string,
color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string,
}}>
- {this.content}
- {/* Displays a message to the user to add more flashcards if they are in practice mode and no flashcards are there. */}
- <p
- style={{
- display: !this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)] && this.layoutDoc.filterOp === cardMode.PRACTICE ? 'flex' : 'none',
- justifyContent: 'center',
- alignItems: 'center',
- height: '100%',
- zIndex: '-1',
- }}>
- Add flashcards!
- </p>
- {/* Displays a message to the user that a flashcard was recently missed if they had previously gotten it wrong. */}
+ {!this._practiceMessage && !this._filterMessage ? (
+ this.content
+ ) : (
+ <p className="message">
+ {this._filterMessage}
+ {'\n'}
+ {this._practiceMessage}
+ </p>
+ )}
+ {!this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)] && this.layoutDoc.practiceMode === practiceMode.PRACTICE ? <p className="message">Add flashcards </p> : null}
<p
+ className="missed-message"
style={{
color: 'red',
+ fontWeight: 'bold',
zIndex: '999',
position: 'relative',
left: '10px',
top: '10px',
- display: this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)] ? (this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.practiceField] === practiceVal.MISSED ? 'block' : 'none') : 'none',
+ width: '10px',
+ display: this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)]
+ ? this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.practiceField] === practiceVal.MISSED && this.layoutDoc.practiceMode === practiceMode.PRACTICE && !this._practiceMessage
+ ? 'block'
+ : 'none'
+ : 'none',
}}>
Recently missed!
</p>
- {this.Document._chromeHidden ? null : this.buttons}
+ {!this.containsDifTypes() && this.carouselItems.length !== 0 ? this.menu : null}
+ {this.Document._chromeHidden || (!this._filterMessage && !this._practiceMessage) ? this.buttons : null}
</div>
);
}