aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/FilterPanel.scss18
-rw-r--r--src/client/views/FilterPanel.tsx3
-rw-r--r--src/client/views/InkingStroke.tsx14
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx221
-rw-r--r--src/client/views/global/globalScripts.ts26
-rw-r--r--src/client/views/nodes/IconTagBox.tsx23
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.scss56
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx319
8 files changed, 482 insertions, 198 deletions
diff --git a/src/client/views/FilterPanel.scss b/src/client/views/FilterPanel.scss
index 0b9076f3b..34c3d2fc1 100644
--- a/src/client/views/FilterPanel.scss
+++ b/src/client/views/FilterPanel.scss
@@ -283,6 +283,8 @@
.hotkey-title{
top: 6px;
position: relative;
+ cursor: text;
+
}
.hotkey-title-input{
@@ -290,6 +292,8 @@
border: none;
border-color: transparent;
outline: none;
+ cursor: text;
+
}
}
@@ -345,6 +349,20 @@
}
+
+.drawing-box{
+ position: absolute;
+ z-index: 10000;
+ border-color: black;
+ border-style: solid;
+ border-width: medium;
+ border-radius: 10%;
+ background-color: #323232;
+
+
+
+
+}
// .sliderBox-outerDiv {
// width: 30%;// width: calc(100% - 14px); // 14px accounts for handles that are at the max value of the slider that would extend outside the box
// height: 40; // height: 100%;
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 17c5cb173..ca4e4df84 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -51,10 +51,13 @@ interface filterProps {
@observer
export class FilterPanel extends ObservableReactComponent<filterProps> {
@observable _selectedFacetHeaders = new Set<string>();
+ public static Instance: FilterPanel;
+
constructor(props: any) {
super(props);
makeObservable(this);
+ FilterPanel.Instance = this;
}
/**
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 62b79dd5a..a117ff3c3 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -447,13 +447,13 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>()
}),
icon: 'paint-brush',
});
- cm?.addItem({
- description: 'Create a hotkey',
- event: action(() => {
- InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton;
- }),
- icon: 'satellite',
- });
+ // cm?.addItem({
+ // description: 'Create a hotkey',
+ // event: action(() => {
+ // InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton;
+ // }),
+ // icon: 'satellite',
+ // });
},
};
return (
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 52f01e239..5dafb1088 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -28,6 +28,8 @@ import { SettingsManager } from '../../util/SettingsManager';
import { Tooltip } from '@mui/material';
import { dropActionType } from '../../util/DropActionTypes';
import { List } from '../../../fields/List';
+import { DocCast } from '../../../fields/Types';
+import { SelectionManager } from '../../util/SelectionManager';
enum cardSortings {
Time = 'time',
@@ -35,6 +37,7 @@ enum cardSortings {
Color = 'color',
Custom = 'custom',
Chat = 'chat',
+ Tag = 'tag',
None = '',
}
@observer
@@ -91,7 +94,9 @@ export class CollectionCardView extends CollectionSubView() {
childPairStringListAndUpdateSortDesc = async () => {
const sortDesc = await this.childPairStringList(); // Await the promise to get the string result
GPTPopup.Instance.setSortDesc(sortDesc.join());
- GPTPopup.Instance.onSortComplete = (sortResult: string) => this.processGptOutput(sortResult);
+ GPTPopup.Instance.onSortComplete = (sortResult: string, questionType: string, tag?: string) => this.processGptOutput(sortResult, questionType, tag);
+ GPTPopup.Instance.onQuizRandom = () => this.quizMode()
+
};
componentDidMount(): void {
@@ -103,9 +108,17 @@ export class CollectionCardView extends CollectionSubView() {
});
+ // Reaction to cardSort changes
this._disposers.sort = reaction(
- () => ({ cardSort: this.cardSort }),
- ({ cardSort}) => (cardSort === cardSortings.Chat ? this.openChatPopup() : GPTPopup.Instance.setVisible(false))
+ () => this.cardSort,
+ (cardSort) => {
+ if (cardSort === cardSortings.Chat) {
+ this.openChatPopup();
+ } else {
+ GPTPopup.Instance.setVisible(false);
+ }
+ // Force re-render to see if this resolves the sorting issue
+ }
);
@@ -121,6 +134,7 @@ export class CollectionCardView extends CollectionSubView() {
}
@computed get cardSort() {
+ // console.log(StrCast(this.Document.cardSort) as any as cardSortings)
return StrCast(this.Document.cardSort) as any as cardSortings;
}
@@ -151,6 +165,16 @@ export class CollectionCardView extends CollectionSubView() {
return regularDocs;
}
+ quizMode () {
+
+ const randomIndex = Math.floor(Math.random() * this.childDocs.length)
+ console.log('hiiiiiii')
+
+ SelectionManager.DeselectAll()
+ DocumentView.SelectView(DocumentView.getDocumentView(this.childDocs[randomIndex]), false)
+
+ }
+
/**
@@ -290,13 +314,48 @@ export class CollectionCardView extends CollectionSubView() {
};
- @computed get sortedDocs() {
+ get sortedDocs() {
// console.log("hi hi hi")
// console.log(this.layoutDoc.cardSort_isDesc + "layoutdoc desc")
- console.log(this.cardSort + "card sort")
+ // console.log(this.cardSort + "card sort")
- return this.sort(this.childDocsWithoutLinks, this.cardSort, BoolCast(this.layoutDoc.cardSort_isDesc), this._docDraggedIndex);
+ return this.sort(this.childDocsWithoutLinks, this.cardSort, BoolCast(this.Document.cardSort_isDesc), this._docDraggedIndex);
}
+
+ tagValue(doc: Doc) {
+ const keys = StrListCast(Doc.UserDoc().myFilterHotKeyTitles);
+
+ const isTagActive = (buttonID: number) => {
+ return BoolCast(doc[StrCast(Doc.UserDoc()[keys[buttonID]])]);
+ };
+
+ let base = '';
+ let fraction = '';
+
+ for (let i = 0; i < keys.length; i++) {
+ if (isTagActive(i)) {
+ if (base === '') {
+ base = i.toString(); // First active tag becomes the base
+ } else {
+ fraction += i.toString(); // Subsequent active tags become part of the fraction
+ }
+ }
+ }
+
+ // If no tag was active, return 0 by default
+ if (base === '') {
+ return 0;
+ }
+
+ // Construct the final number by appending the fraction if it exists
+ const numberString = fraction ? `${base}.${fraction}` : base;
+
+ // Convert the result to a number and return
+ return Number(numberString);
+ }
+
+
+
/**
* Called in the sortedDocsType method. Compares the cards' value in regards to the desired sort type-- earlier cards are move to the
* front, latter cards to the back
@@ -305,7 +364,8 @@ export class CollectionCardView extends CollectionSubView() {
* @param isDesc
* @returns
*/
- sort = (docs: Doc[], sortType: cardSortings, isDesc: boolean, dragIndex: number) => {
+ @action sort = (docs: Doc[], sortType: cardSortings, isDesc: boolean, dragIndex: number) => {
+ // console.log('hiiii')
// if (sortType === cardSortings.None) return docs;
// if(sortType !== cardSortings.None){
@@ -319,12 +379,13 @@ export class CollectionCardView extends CollectionSubView() {
case cardSortings.Color:
return [ClientUtils.hexToHsv(StrCast(docA.backgroundColor)),
ClientUtils.hexToHsv(StrCast(docB.backgroundColor))];
- case cardSortings.Custom:
- return [CollectionCardView.getButtonGroup(this.cardSort_customField, docA) ?? 9999,
- CollectionCardView.getButtonGroup(this.cardSort_customField, docB) ?? 9999];
+ case cardSortings.Tag:
+ return [this.tagValue(docA) ?? 9999,
+ this.tagValue(docB) ?? 9999];
case cardSortings.Chat:
- return [NumCast(docA.chat) ?? 9999,
- NumCast(docB.chat) ?? 9999]
+ return [NumCast(docA.chatIndex) ?? 9999,
+ NumCast(docB.chatIndex) ?? 9999]
+
default:
return [StrCast(docA.type), StrCast(docB.type)]
@@ -487,12 +548,19 @@ export class CollectionCardView extends CollectionSubView() {
* Converts the gpt output into a hashmap that can be used for sorting. lists are seperated by ==== while elements within the list are seperated by ~~~~~~
* @param gptOutput
*/
- @action processGptOutput = (gptOutput: string) => {
+ @action processGptOutput = (gptOutput: string, questionType: string, tag?: string) => {
console.log("HIIII")
console.log(StrCast(this.Document.cardSort) + "cardSort")
// Split the string into individual list items
const listItems = gptOutput.split('======').filter(item => item.trim() !== '');
+
+
+ if (questionType == '2' || questionType == '4'){
+ this.childDocs.forEach(d => {
+ d['chatFilter'] = false
+ })
+ }
// console.log(listItems + " LISTT");
// Debug: print the map contents
@@ -509,10 +577,47 @@ export class CollectionCardView extends CollectionSubView() {
// console.log("ITEM:", normalizedItem);
if (doc) {
- doc.chat = index;
+ switch (questionType){
+ case '6':
+ doc.chatIndex = index
+ console.log(index)
+ break
+ case '1':
+ const allHotKeys = StrListCast(Doc.UserDoc().myFilterHotKeyTitles)
+
+ let myTag = ''
+
+ if (tag){
+ for (let i=0; i< allHotKeys.length; i++){
+ if (tag.includes(allHotKeys[i])){
+ myTag = StrCast(Doc.UserDoc()[allHotKeys[i]])
+ break
+ }
+
+ else if (tag.includes(StrCast(Doc.UserDoc()[allHotKeys[i]]))){
+ myTag = StrCast(Doc.UserDoc()[allHotKeys[i]])
+ break
+ }
+ }
+
+ if (myTag != ''){
+ doc[myTag] = true
+ }
+ }
+ break
+ case '2':
+ case '4':
+ doc['chatFilter'] = true
+ Doc.setDocFilter(DocCast(this.Document.embedContainer), 'chatFilter', true, 'match');
+ break
+
+
+
+ }
} else {
console.warn(`No matching document found for item: ${normalizedItem}`);
}
+
});
}
@@ -528,100 +633,20 @@ export class CollectionCardView extends CollectionSubView() {
const sortDesc = await this.childPairStringList(); // Await the promise to get the string result
GPTPopup.Instance.setCardsDoneLoading(true); // Set dataDoneLoading to true after data is loaded
GPTPopup.Instance.setSortDesc(sortDesc.join());
- GPTPopup.Instance.onSortComplete = (sortResult: string) => this.processGptOutput(sortResult);
- };
-
- /**
- * Renders the buttons to customize sorting depending on which group the card belongs to and the amount of total groups
- * @param doc
- * @param cardSort
- * @returns
- */
- renderButtons = (doc: Doc, cardSort: cardSortings): JSX.Element | null => {
- // if (cardSort !== cardSortings.Custom) return null;
-
- const amButtons = 4
-
- // const amButtons = Math.max(
- // 4,
- // this.childDocs?.reduce((set, d) => {
- // if (this.cardSort_customField) {
- // set.add(NumCast(d[this.cardSort_customField]));
- // }
- // return set;
- // }, new Set<number>()).size ?? 0
- // );
-
- // const activeButtonIndex = CollectionCardView.getButtonGroup(this.cardSort_customField, doc);
-
- const totalWidth = amButtons * 72 + amButtons * 2 * 5 + 6;
-
- const iconMap: { [key: number]: any } = {
- 0: 'star',
- 1: 'heart',
- 2: 'cloud',
- 3: 'bolt'
- };
-
- return (
- <div className="card-button-container" style={{ width: `${totalWidth}px`, fontSize: '50px' }}>
- {numberRange(amButtons).map(i => (
- <Tooltip key={i} title={<div className="dash-tooltip">Click to add/remove this card from the {iconMap[i]} group</div>}>
- <button type="button" onClick={() => this.toggleButton(doc, iconMap[i] )}>
- {this.getButtonIcon(doc, iconMap[i])}
- </button>
- </Tooltip>
- ))}
- </div>
- );
- };
-
- /**
- * Toggles the buttons between on and off when creating custom sort groupings/changing those created by gpt
- * @param childPairIndex
- * @param buttonID
- * @param doc
- */
- toggleButton = undoable((doc: Doc, icon: string) => {
-
-
-
- // this.cardSort_customField && (doc[this.cardSort_customField] = buttonID);
-
- // doc.cardSort_activeIcons = new List<string>()
-
-
- // const list = StrListCast(doc.cardSort_activeIcons);
- // doc.cardSort_activeIcons = new List<string>(list.includes(icon) ? list.filter(d => d !== icon) : [...list, icon]);
-
- BoolCast(doc[icon]) ? doc[icon] = false : doc[icon] = true
-
-
-
- // StrListCast(doc.cardSort_activeIcons).push(iconMap[buttonID])
- }, 'toggle card tag');
-
-
- getButtonIcon = (doc: Doc, icon: any): JSX.Element => {
-
- // const isActive = StrListCast(doc.cardSort_activeIcons).includes(icon)
- const isActive = doc[icon]
-
- // console.log(StrListCast(doc.cardSort_activeIcons))
- const color = isActive ? '#4476f7' : '#323232';
-
- return <FontAwesomeIcon icon={icon} size="lg" style={{ color }} />;
+ GPTPopup.Instance.onSortComplete = (sortResult: string, questionType: string, tag?: string) => this.processGptOutput(sortResult, questionType, tag);
+ GPTPopup.Instance.onQuizRandom = () => this.quizMode()
};
/**
* Actually renders all the cards
*/
renderCards = () => {
+ // console.log('christ')
const anySelected = this.childDocs.some(doc => DocumentView.SelectedDocs().includes(doc));
const isEmpty = this.childDocsWithoutLinks.length === 0;
const isDesc = BoolCast(this.Document.cardSort_isDesc)
- console.log(this.childDocsWithoutLinks.length + "length")
+ // console.log(this.childDocsWithoutLinks.length + "length")
if (isEmpty) {
return (
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index a48e3f9d9..1efcd84e4 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -146,7 +146,7 @@ ScriptingGlobals.add(function showFreeform(attr: 'center' | 'grid' | 'snaplines'
}
// prettier-ignore
- const map: Map<'flashcards' | 'center' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'chat' | 'up' | 'down' | 'pile' | 'toggle-chat',
+ const map: Map<'flashcards' | 'center' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'chat' | 'up' | 'down' | 'pile' | 'toggle-chat' | 'tag',
{
waitForRender?: boolean;
checkResult: (doc: Doc) => any;
@@ -193,6 +193,10 @@ ScriptingGlobals.add(function showFreeform(attr: 'center' | 'grid' | 'snaplines'
checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "color",
setDoc: (doc: Doc, dv: DocumentView) => doc.cardSort === "color" ? doc.cardSort = '' : doc.cardSort = 'color',
}],
+ ['tag', {
+ checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "tag",
+ setDoc: (doc: Doc, dv: DocumentView) => doc.cardSort === "tag" ? doc.cardSort = '' : doc.cardSort = 'tag',
+ }],
// ['heart', {
// checkResult: (doc: Doc) => isAttrFiltered('heart'),
// setDoc: (doc: Doc, dv: DocumentView) => {
@@ -221,16 +225,16 @@ ScriptingGlobals.add(function showFreeform(attr: 'center' | 'grid' | 'snaplines'
// }
// }],
- ['chat', {
- checkResult: (doc: Doc) => {
+ // ['chat', {
+ // checkResult: (doc: Doc) => {
- if (StrCast(doc?.cardSort) === "chat"){
- return true
- }} ,
- setDoc: (doc: Doc, dv: DocumentView) => {
- doc.cardSort === "chat" ? doc.cardSort = '' : doc.cardSort = 'chat';
- },
- }],
+ // if (StrCast(doc?.cardSort) === "chat"){
+ // return true
+ // }} ,
+ // setDoc: (doc: Doc, dv: DocumentView) => {
+ // doc.cardSort === "chat" ? doc.cardSort = '' : doc.cardSort = 'chat';
+ // },
+ // }],
['up', {
checkResult: (doc: Doc) => BoolCast(!doc?.cardSort_isDesc),
setDoc: (doc: Doc, dv: DocumentView) => {
@@ -248,6 +252,8 @@ ScriptingGlobals.add(function showFreeform(attr: 'center' | 'grid' | 'snaplines'
setDoc: (doc: Doc, dv: DocumentView) => {
GPTPopup.Instance.setVisible(!GPTPopup.Instance.visible);
GPTPopup.Instance.setMode(GPTPopupMode.SORT);
+ doc.cardSort === "chat" ? doc.cardSort = '' : doc.cardSort = 'chat';
+
},
}],
diff --git a/src/client/views/nodes/IconTagBox.tsx b/src/client/views/nodes/IconTagBox.tsx
index c72d48ef5..8aa6bff2b 100644
--- a/src/client/views/nodes/IconTagBox.tsx
+++ b/src/client/views/nodes/IconTagBox.tsx
@@ -26,6 +26,9 @@ import { setupMoveUpEvents } from "../../../ClientUtils";
import { returnFalse } from "../../../ClientUtils";
import { emptyFunction } from "../../../Utils";
import { CollectionViewType } from "../../documents/DocumentTypes";
+import { SnappingManager } from "../../util/SnappingManager";
+import { MainView } from "../MainView";
+import { PropertiesView } from "../PropertiesView";
export interface IconTagProps {
@@ -129,7 +132,7 @@ export class IconTagBox extends ObservableReactComponent<IconTagProps> {
renderButtons = (doc: Doc): JSX.Element | null => {
// if (cardSort !== cardSortings.Custom) return null;
- const amButtons = StrListCast(Doc.UserDoc().myFilterHotKeyTitles).length
+ const amButtons = (StrListCast(Doc.UserDoc().myFilterHotKeyTitles).length) + 1
const keys = StrListCast(Doc.UserDoc().myFilterHotKeyTitles)
@@ -146,7 +149,7 @@ export class IconTagBox extends ObservableReactComponent<IconTagProps> {
// const activeButtonIndex = CollectionCardView.getButtonGroup(this.cardSort_customField, doc);
- const totalWidth = amButtons * 35 + amButtons * 2 * 5 + 6;
+ const totalWidth = (amButtons -1) * 35 + (amButtons -1) * 2 * 5 + 6;
const iconMap = (buttonID: number) => {
return StrCast(Doc.UserDoc()[keys[buttonID]])
@@ -169,17 +172,31 @@ export class IconTagBox extends ObservableReactComponent<IconTagProps> {
fontSize: '50px'
}}
>
- {numberRange(amButtons).map(i => (
+ {numberRange(amButtons-1).map(i => (
<Tooltip key={i} title={<div className="dash-tooltip">Click to add/remove this card from the {iconMap(i)} group</div>}>
<button key = {i} type="button" onClick={() => this.toggleButton(doc, iconMap(i) )}>
{this.getButtonIcon(doc, iconMap(i))}
</button>
</Tooltip>
))}
+
+ {/* <Tooltip title={<div className="dash-tooltip">Click to customize these icons</div>}>
+ <button type="button" onClick={() => this.openHotKeyMenu() }>
+ <FontAwesomeIcon icon='gear' style={{ color: '#17438a', height: '30px', width: '30px'}} />
+ </button>
+ </Tooltip> */}
</div>
);
};
+ openHotKeyMenu = () => {
+ SnappingManager.PropertiesWidth < 5 && SnappingManager.SetPropertiesWidth(0);
+ SnappingManager.SetPropertiesWidth(MainView.Instance.propertiesWidth() < 15 ? Math.min(MainView.Instance._dashUIWidth - 50, 250) : 0);
+
+ PropertiesView.Instance.CloseAll()
+ PropertiesView.Instance.openFilters = true
+ }
+
/**
* Toggles the buttons between on and off when creating custom sort groupings/changing those created by gpt
* @param childPairIndex
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.scss b/src/client/views/pdf/GPTPopup/GPTPopup.scss
index eaa3eaebf..1defd1a7f 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.scss
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.scss
@@ -78,15 +78,63 @@ $highlightedText: #82e0ff;
align-items: center;
flex-direction: column;
- transform: translateY(30px);
+ .inputWrapper{
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 60px;
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ background-color: white;
+
+ }
.searchBox-input{
- transform: translateY(-15px);
- height: 50px;
+ height: 40px;
border-radius: 10px;
+ position: absolute;
+ bottom: 10px;
border-color: #5b97ff;
+ width: 90%
+ }
+
+ .chat-wrapper {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ max-height: calc(100vh - 80px); /* Height minus the input box and some padding */
+ overflow-y: auto;
+ padding-bottom: 60px; /* Space for the input */
+ }
+
+ .chat-bubbles {
+ margin-top: 20px;
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ }
+
+ .chat-bubble {
+ padding: 10px;
+ margin-bottom: 10px;
+ border-radius: 10px;
+ max-width: 60%;
}
+
+ .user-message {
+ background-color: #283d53;
+ align-self: flex-end;
+ color: whitesmoke;
+ }
+
+ .chat-message {
+ background-color: #367ae7;
+ align-self: flex-start;
+ color:whitesmoke;
+ }
+
@@ -98,6 +146,8 @@ $highlightedText: #82e0ff;
+
+
}
// button {
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index d216cc421..1b44508d7 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -34,6 +34,13 @@ export enum GPTPopupMode {
QUIZ
}
+export enum GPTQuizType {
+ CURRENT = 0,
+ CHOOSE = 1,
+ MULTIPLE = 2
+
+}
+
@@ -151,7 +158,8 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
this.sortDesc = t;
};
- @observable onSortComplete?: (sortResult: string) => void;
+ @observable onSortComplete?: (sortResult: string, questionType: string, tag?: string) => void;
+ @observable onQuizRandom?: () => void;
@observable cardsDoneLoading = false;
@action setCardsDoneLoading(done: boolean) {
@@ -165,6 +173,9 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
this.sortRespText = resp
}
+ //mode where gpt says to select a specific card
+ //
+
@observable chatSortPrompt: string = ""
@@ -179,39 +190,65 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
this.quizAnswer = e.target.value;
});
+
+ @observable correctAnswer: string = ''
+ @observable setCorrectAnswer = (s: string) => {
+ this.correctAnswer = s
+ }
+
generateQuiz = async () => {
this.setLoading(true);
this.setSortDone(false);
+ const quizType = this.quizMode;
const selected = DocumentView.SelectedDocs().lastElement();
- const questionText = 'Question: ' + StrCast(selected['gptInputText']);
- if (StrCast(selected['gptRubric']) === '') {
- const rubricText = 'Rubric: ' + await this.generateRubric(StrCast(selected['gptInputText']), selected)
- }
+ const questionText = 'Question: ' + StrCast(selected['gptInputText']);
- const rubricText = 'Rubric: ' + (StrCast(selected['gptRubric']))
- // const rubricText = 'Rubric: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text);
- const queryText = questionText + ' UserAnswer: ' + this.quizAnswer + '. ' + 'Rubric' + rubricText;
+ if (StrCast(selected['gptRubric']) === '') {
+ const rubricText = 'Rubric: ' + await this.generateRubric(StrCast(selected['gptInputText']), selected)
+ }
- try {
- const res = await gptAPICall(queryText, GPTCallType.QUIZ);
- if (!res) {
- console.error('GPT call failed');
- return;
- }
- console.log(res)
- this.setQuizResp(res)
+ const rubricText = 'Rubric: ' + (StrCast(selected['gptRubric']))
+ // const rubricText = 'Rubric: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text);
+ const queryText = questionText + ' UserAnswer: ' + this.quizAnswer + '. ' + 'Rubric' + rubricText;
- this.setLoading(false);
- this.setSortDone(true);
+ try {
+ const res = await gptAPICall(queryText, GPTCallType.QUIZ);
+ if (!res) {
+ console.error('GPT call failed');
+ return;
+ }
+ console.log(res)
+ this.setQuizResp(res)
+ this.conversationArray.push(res)
+
+ this.setLoading(false);
+ this.setSortDone(true);
+
+ // this._outputValue = res;
+ } catch (err) {
+ console.error('GPT call failed');
+ }
+
+
+ if (this.onQuizRandom){
+ this.onQuizRandom()
+ }
- // this._outputValue = res;
- } catch (err) {
- console.error('GPT call failed');
- }
+
+
+
+
+ // switch(quizType){
+ // default:
+
+ // }
+
+
+
}
@@ -254,11 +291,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
}
-
- /**
- * Sorts cards in the CollectionCardDeckView
- */
- generateSort = async () => {
+ generateCard = async () => {
console.log(this.chatSortPrompt + "USER PROMPT")
this.setLoading(true);
this.setSortDone(false);
@@ -268,17 +301,50 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
}
try {
- const res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
+ // const res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
+ const questionType = await gptAPICall(this.chatSortPrompt, GPTCallType.TYPE);
+ const questionNumber = questionType.split(' ')[0]
+ console.log(questionType)
+ let res = ''
+
+ switch (questionNumber) {
+ case '1':
+ case '2':
+ case '4':
+ res = await gptAPICall(this.sortDesc, GPTCallType.SUBSET, this.chatSortPrompt);
+ break
+ case '6':
+ res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
+ break
+ default:
+
+ const selected = DocumentView.SelectedDocs().lastElement();
+ const questionText = StrCast(selected!['gptInputText']);
+
+
+ res = await gptAPICall(questionText, GPTCallType.INFO, this.chatSortPrompt);
+ break
+ }
+
+
+ // const res = await gptAPICall(this.sortDesc, GPTCallType.SUBSET, this.chatSortPrompt);
// Trigger the callback with the result
if (this.onSortComplete) {
- this.onSortComplete(res || 'Something went wrong :(');
+ this.onSortComplete(res || 'Something went wrong :(', questionNumber, questionType.split(' ').slice(1).join(' '));
+
+ let explanation = res
+
+ if (questionType != '5' && questionType != '3'){
// Extract explanation surrounded by ------ at the top or both at the top and bottom
const explanationMatch = res.match(/------\s*([\s\S]*?)\s*(?:------|$)/) || [];
- const explanation = explanationMatch[1] ? explanationMatch[1].trim() : 'No explanation found';
+ explanation = explanationMatch[1] ? explanationMatch[1].trim() : 'No explanation found';
+ }
// Set the extracted explanation to sortRespText
this.setSortRespText(explanation);
+ this.conversationArray.push(this.sortRespText)
+ this.scrollToBottom()
console.log(res);
}
@@ -289,6 +355,43 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
this.setLoading(false);
this.setSortDone(true);
};
+
+
+ // /**
+ // * Sorts cards in the CollectionCardDeckView
+ // */
+ // generateSort = async () => {
+ // console.log(this.chatSortPrompt + "USER PROMPT")
+ // this.setLoading(true);
+ // this.setSortDone(false);
+
+ // if (this.regenerateCallback) {
+ // await this.regenerateCallback();
+ // }
+
+ // try {
+ // const res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
+
+ // // Trigger the callback with the result
+ // if (this.onSortComplete) {
+ // this.onSortComplete(res || 'Something went wrong :(');
+
+ // // Extract explanation surrounded by ------ at the top or both at the top and bottom
+ // const explanationMatch = res.match(/------\s*([\s\S]*?)\s*(?:------|$)/) || [];
+ // const explanation = explanationMatch[1] ? explanationMatch[1].trim() : 'No explanation found';
+
+ // // Set the extracted explanation to sortRespText
+ // this.setSortRespText(explanation);
+
+ // console.log(res);
+ // }
+ // } catch (err) {
+ // console.error(err);
+ // }
+
+ // this.setLoading(false);
+ // this.setSortDone(true);
+ // };
/**
@@ -422,19 +525,40 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
super(props);
makeObservable(this);
GPTPopup.Instance = this;
+ this.messagesEndRef = React.createRef();
+
}
+ private messagesEndRef: React.RefObject<HTMLDivElement>;
+
+
+ scrollToBottom = () => {
+ setTimeout(() => {
+ // Code to execute after 1 second (1000 ms)
+ if (this.messagesEndRef.current) {
+
+ this.messagesEndRef.current.scrollIntoView({ behavior: 'smooth', block: 'end' });
+ }
+
+ }, 50);
+ }
+
componentDidUpdate = () => {
if (this.loading) {
this.setDone(false);
}
};
+ @observable quizMode : GPTQuizType = GPTQuizType.CURRENT
+ @action setQuizMode (g: GPTQuizType) {
+ this.quizMode = g
+ }
+
cardMenu = () => (
<div className="btns-wrapper-gpt">
<Button
- tooltip="Have ChatGPT sort your cards for you!"
- text="Sort Cards!"
+ tooltip="Have ChatGPT sort, tag, define, or filter your cards for you!"
+ text="Modify/Sort Cards!"
onClick={() => this.setMode(GPTPopupMode.SORT)}
color={StrCast(Doc.UserDoc().userVariantColor)}
type={Type.TERT}
@@ -450,7 +574,16 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
<Button
tooltip="Test your knowledge with ChatGPT!"
text="Quiz Cards!"
- onClick={() => this.setMode(GPTPopupMode.QUIZ)}
+ onClick={() => {
+ this.conversationArray = ['Define the selected card!']
+ this.setMode(GPTPopupMode.QUIZ)
+ if (this.onQuizRandom){
+ this.onQuizRandom()
+ }
+
+
+
+ }}
color={StrCast(Doc.UserDoc().userVariantColor)}
type={Type.TERT}
style={{
@@ -464,62 +597,94 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
/>
</div>
)
+
+ @observable conversationArray: string[] = ["Hi! In this pop up, you can ask ChatGPT questions about your documents and filter / sort them. If you're not sure if something is possible-- just ask!"]
+
+
+ handleKeyPress = async (e: React.KeyboardEvent, isSort: boolean) => {
+ if (e.key === 'Enter') {
+ e.stopPropagation();
+
+ if (isSort) {
+ this.conversationArray.push(this.chatSortPrompt);
+ await this.generateCard();
+ this.chatSortPrompt = ''
+
+ } else {
+ this.conversationArray.push(this.quizAnswer);
+ await this.generateQuiz();
+ this.quizAnswer = ''
+
+ }
+
+ this.scrollToBottom();
+ }
+ }
cardActual = (opt: GPTPopupMode) => {
const isSort = opt === GPTPopupMode.SORT
// if (opt === GPTPopupMode.SORT) {
return (
- !this.sortDone ? (
- <>
- <div className="btns-wrapper-gpt">
+ // !this.sortDone ? (
+ // <>
+ <div className="btns-wrapper-gpt">
+ {/* Chat bubble container with scroll */}
+ <div className="chat-wrapper">
+ <div className="chat-bubbles">
+ {this.conversationArray.map((message, index) => (
+ <div
+ key={index}
+ className={`chat-bubble ${index % 2 === 1 ? 'user-message' : 'chat-message'}`}
+ >
+ {message}
+ </div>
+ ))}
+
+ {/* Conditional Loading message */}
+ {(!this.cardsDoneLoading || this.loading) && (
+ <div className={`chat-bubble chat-message`}>
+ ...
+ </div>
+ )}
+ </div>
+
+ <div ref={this.messagesEndRef} style= {{height: '100px'}} />
+
+ </div>
+
+ <div className="inputWrapper">
<input
className="searchBox-input"
defaultValue=""
autoComplete="off"
onChange={isSort ? this.sortPromptChanged : this.quizAnswerChanged}
- onKeyDown={e => {
- if (e.key === 'Enter') {
- isSort ? this.generateSort() : this.generateQuiz();
+ onKeyDown={(e) => {
+ this.handleKeyPress(e, isSort)
+
+
}
- e.stopPropagation();
- }}
+ }
type="text"
- placeholder={`${isSort ? 'How do you want to sort your cards?' : 'Define the selected card?'}`}
- id="search-input"
- style={{ width: '100%' }}
- />
- {/* </div>
- <div className="btns-wrapper-gpt"> */}
- <Button
- tooltip={`${isSort ? 'HaveChatGPT sort ypur cards for you!' : 'See how close you get to the right answer!'}`}
- text={`${isSort ? 'Sort!' : 'Check!'}`}
- onClick={isSort ? this.generateSort : this.generateQuiz}
- color={StrCast(Doc.UserDoc().userVariantColor)}
- type={Type.TERT}
- style={{
- width: '100%',
- textAlign: 'center',
- color: '#ffffff',
- fontSize: '16px',
- height: '40%',
-
- }}
- />
- </div>
- </>
- ) : (
- <div>
- <div className="content-wrapper">
- <p>{this.text === 'Something went wrong :(' ? 'Something went wrong :(' : `${isSort ? this.sortRespText : this.quizRespText}`}</p>
- <IconButton
- tooltip="Generate Again"
- onClick={() => this.setSortDone(false)}
- icon={<FontAwesomeIcon icon="redo-alt" size="lg" />}
- color={StrCast(Doc.UserDoc().userVariantColor)}
+ placeholder={`${isSort ? 'Have ChatGPT sort, tag, define, or filter your cards for you!' : 'Define the selected card!'}`}
/>
</div>
</div>
- )
+
+
+ // </>
+ // ) : (
+ // <div>
+ // <div className="content-wrapper">
+ // <p>{this.text === 'Something went wrong :(' ? 'Something went wrong :(' : `${isSort ? this.sortRespText : this.quizRespText}`}</p>
+ // <IconButton
+ // tooltip="Generate Again"
+ // onClick={() => this.setSortDone(false)}
+ // icon={<FontAwesomeIcon icon="redo-alt" size="lg" />}
+ // color={StrCast(Doc.UserDoc().userVariantColor)}
+ // />
+ // </div>
+ // </div>
+ // )
);
// } else if (opt === GPTPopupMode.QUIZ) {
// return (
@@ -563,10 +728,10 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
};
sortBox = () => (
- <div>
+ <div style = {{height: '80%'}}>
{this.heading(this.mode === GPTPopupMode.SORT ? 'SORTING' : 'QUIZ')}
<>
- {!this.cardsDoneLoading || this.loading ? (
+ {!this.cardsDoneLoading? (
<div className="content-wrapper">
<div className="loading-spinner">
<ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
@@ -737,7 +902,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
tooltip="back"
icon={<CgCornerUpLeft size="16px" />}
onClick={() => this.mode = GPTPopupMode.CARD}
- style = {{right: '-20%'}}
+ style = {{right: '50px', position: 'absolute'}}
/>
)}
<IconButton