From 45aa1b54ab37d821257fb00b3be5ef5eca03ef2c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 29 Jan 2025 15:09:10 -0500
Subject: generlized some of cardDeck ui.  showTags is under View for all
 collections.  chat popup is available for all docs, but only works for card
 views.   added clear filters button for chat popup.

---
 .../views/collections/CollectionCardDeckView.tsx   | 106 ++++++++++-----------
 1 file changed, 53 insertions(+), 53 deletions(-)

(limited to 'src/client/views/collections/CollectionCardDeckView.tsx')

diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index b40aa37de..f24673c39 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -56,7 +56,6 @@ export class CollectionCardView extends CollectionSubView() {
     constructor(props: SubCollectionViewProps) {
         super(props);
         makeObservable(this);
-        this.setRegenerateCallback();
     }
     protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
         this._dropDisposer?.();
@@ -74,23 +73,19 @@ export class CollectionCardView extends CollectionSubView() {
     @computed get _maxRowCount() {
         return Math.ceil(this.cardDeckWidth / this.cardWidth);
     }
-    /**
-     * Callback to ensure gpt's text versions of the child docs are updated
-     */
-    setRegenerateCallback = () => GPTPopup.Instance.setRegenerateCallback(this.childPairStringListAndUpdateSortDesc);
 
     /**
      * update's gpt's doc-text list and initializes callbacks
      */
-    @action
-    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, questionType: string, tag?: string) => this.processGptOutput(sortResult, questionType, tag);
-        GPTPopup.Instance.onQuizRandom = () => this.quizMode();
-    };
+    childPairStringListAndUpdateSortDesc = () =>
+        this.childPairStringList().then(sortDesc => {
+            GPTPopup.Instance.setSortDesc(sortDesc.join());
+            GPTPopup.Instance.onSortComplete = this.processGptOutput;
+            GPTPopup.Instance.onQuizRandom = this.quizMode;
+        });
 
     componentDidMount() {
+        GPTPopup.Instance.setRegenerateCallback(this.Document, this.childPairStringListAndUpdateSortDesc);
         this._props.setContentViewBox?.(this);
         // if card deck moves, then the child doc views are hidden so their screen to local transforms will return empty rectangles
         // when inquired from the dom (below in childScreenToLocal).  When the doc is actually rendered, we need to act like the
@@ -112,6 +107,10 @@ export class CollectionCardView extends CollectionSubView() {
     }
 
     componentWillUnmount() {
+        GPTPopup.Instance.setSortDesc('');
+        GPTPopup.Instance.onSortComplete = undefined;
+        GPTPopup.Instance.onQuizRandom = undefined;
+        GPTPopup.Instance.setRegenerateCallback(undefined, null);
         Object.keys(this._disposers).forEach(key => this._disposers[key]?.());
         this._dropDisposer?.();
     }
@@ -166,8 +165,7 @@ export class CollectionCardView extends CollectionSubView() {
      * When in quiz mode, randomly selects a document
      */
     quizMode = () => {
-        const randomIndex = Math.floor(Math.random() * this.childDocs.length);
-        this.layoutDoc._card_curDoc = this.childDocs[randomIndex];
+        this.layoutDoc._card_curDoc = this.childDocs[Math.floor(Math.random() * this.childDocs.length)];
     };
 
     setHoveredNodeIndex = action((index: number) => {
@@ -437,49 +435,51 @@ export class CollectionCardView extends CollectionSubView() {
      * Processes gpt's output depending on the type of question the user asked. Converts gpt's string output to
      * usable code
      * @param gptOutput
+     * @param questionType
+     * @param tag
      */
-    @action
-    processGptOutput = undoable((gptOutput: string, questionType: string, tag?: string) => {
-        // 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;
-            });
-        }
+    processGptOutput = (gptOutput: string, questionType: string, tag?: string) =>
+        undoable(() => {
+            // 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;
+                });
+            }
 
-        if (questionType === '6') {
-            this.Document[this._props.fieldKey + '_sort'] = docSortings.Chat;
-        }
+            if (questionType === '6') {
+                this.Document[this._props.fieldKey + '_sort'] = docSortings.Chat;
+            }
 
-        listItems.forEach((item, index) => {
-            const normalizedItem = item.trim();
-            // find the corresponding Doc in the textToDoc map
-            const doc = this._textToDoc.get(normalizedItem);
-            if (doc) {
-                switch (questionType) {
-                    case '6':
-                        doc.chatIndex = index;
-                        break;
-                    case '1':
-                        if (tag) {
-                            const hashTag = tag.startsWith('#') ? tag : '#' + tag[0].toLowerCase() + tag.slice(1);
-                            const filterTag = Doc.MyFilterHotKeys.map(key => StrCast(key.toolType)).find(key => key.includes(tag)) ?? hashTag;
-                            TagItem.addTagToDoc(doc, filterTag);
-                        }
-                        break;
-                    case '2':
-                    case '4':
-                        doc.chatFilter = true;
-                        Doc.setDocFilter(DocCast(this.Document.embedContainer), 'chatFilter', true, 'match');
-                        break;
+            listItems.forEach((item, index) => {
+                const normalizedItem = item.trim();
+                // find the corresponding Doc in the textToDoc map
+                const doc = this._textToDoc.get(normalizedItem);
+                if (doc) {
+                    switch (questionType) {
+                        case '6':
+                            doc.chatIndex = index;
+                            break;
+                        case '1':
+                            if (tag) {
+                                const hashTag = tag.startsWith('#') ? tag : '#' + tag[0].toLowerCase() + tag.slice(1);
+                                const filterTag = Doc.MyFilterHotKeys.map(key => StrCast(key.toolType)).find(key => key.includes(tag)) ?? hashTag;
+                                TagItem.addTagToDoc(doc, filterTag);
+                            }
+                            break;
+                        case '2':
+                        case '4':
+                            doc.chatFilter = true;
+                            Doc.setDocFilter(DocCast(this.Document), 'chatFilter', true, 'check');
+                            break;
+                    }
+                } else {
+                    console.warn(`No matching document found for item: ${normalizedItem}`);
                 }
-            } else {
-                console.warn(`No matching document found for item: ${normalizedItem}`);
-            }
-        });
-    }, '');
+            });
+        }, '')();
 
     childScreenToLocal = computedFn((doc: Doc, index: number, isSelected: boolean) => () => {
         // need to explicitly trigger an invalidation since we're reading everything from the Dom
-- 
cgit v1.2.3-70-g09d2

