Bläddra i källkod

Normal and live search for bookmarks

unknown 3 år sedan
förälder
incheckning
53d50ca869

+ 28 - 9
client/src/components/Bookmarks/BookmarkGrid/BookmarkGrid.tsx

@@ -9,30 +9,49 @@ import BookmarkCard from '../BookmarkCard/BookmarkCard';
 interface ComponentProps {
 interface ComponentProps {
   categories: Category[];
   categories: Category[];
   totalCategories?: number;
   totalCategories?: number;
+  searching: boolean;
 }
 }
 
 
 const BookmarkGrid = (props: ComponentProps): JSX.Element => {
 const BookmarkGrid = (props: ComponentProps): JSX.Element => {
   let bookmarks: JSX.Element;
   let bookmarks: JSX.Element;
 
 
   if (props.categories.length > 0) {
   if (props.categories.length > 0) {
-    bookmarks = (
-      <div className={classes.BookmarkGrid}>
-        {props.categories.map((category: Category): JSX.Element => <BookmarkCard category={category} key={category.id} />)}
-      </div>
-    );
+    if (props.searching && props.categories[0].bookmarks.length === 0) {
+      bookmarks = (
+        <p className={classes.BookmarksMessage}>
+          No bookmarks match your search criteria
+        </p>
+      );
+    } else {
+      bookmarks = (
+        <div className={classes.BookmarkGrid}>
+          {props.categories.map(
+            (category: Category): JSX.Element => (
+              <BookmarkCard category={category} key={category.id} />
+            )
+          )}
+        </div>
+      );
+    }
   } else {
   } else {
     if (props.totalCategories) {
     if (props.totalCategories) {
       bookmarks = (
       bookmarks = (
-        <p className={classes.BookmarksMessage}>There are no pinned categories. You can pin them from the <Link to='/bookmarks'>/bookmarks</Link> menu</p>
+        <p className={classes.BookmarksMessage}>
+          There are no pinned categories. You can pin them from the{' '}
+          <Link to="/bookmarks">/bookmarks</Link> menu
+        </p>
       );
       );
     } else {
     } else {
       bookmarks = (
       bookmarks = (
-        <p className={classes.BookmarksMessage}>You don't have any bookmarks. You can add a new one from <Link to='/bookmarks'>/bookmarks</Link> menu</p>
+        <p className={classes.BookmarksMessage}>
+          You don't have any bookmarks. You can add a new one from{' '}
+          <Link to="/bookmarks">/bookmarks</Link> menu
+        </p>
       );
       );
     }
     }
   }
   }
 
 
   return bookmarks;
   return bookmarks;
-}
+};
 
 
-export default BookmarkGrid;
+export default BookmarkGrid;

+ 61 - 53
client/src/components/Bookmarks/Bookmarks.tsx

@@ -20,24 +20,23 @@ interface ComponentProps {
   loading: boolean;
   loading: boolean;
   categories: Category[];
   categories: Category[];
   getCategories: () => void;
   getCategories: () => void;
+  searching: boolean;
 }
 }
 
 
 export enum ContentType {
 export enum ContentType {
   category,
   category,
-  bookmark
+  bookmark,
 }
 }
 
 
 const Bookmarks = (props: ComponentProps): JSX.Element => {
 const Bookmarks = (props: ComponentProps): JSX.Element => {
-  const {
-    getCategories,
-    categories,
-    loading
-  } = props;
+  const { getCategories, categories, loading, searching = false } = props;
 
 
   const [modalIsOpen, setModalIsOpen] = useState(false);
   const [modalIsOpen, setModalIsOpen] = useState(false);
   const [formContentType, setFormContentType] = useState(ContentType.category);
   const [formContentType, setFormContentType] = useState(ContentType.category);
   const [isInEdit, setIsInEdit] = useState(false);
   const [isInEdit, setIsInEdit] = useState(false);
-  const [tableContentType, setTableContentType] = useState(ContentType.category);
+  const [tableContentType, setTableContentType] = useState(
+    ContentType.category
+  );
   const [isInUpdate, setIsInUpdate] = useState(false);
   const [isInUpdate, setIsInUpdate] = useState(false);
   const [categoryInUpdate, setCategoryInUpdate] = useState<Category>({
   const [categoryInUpdate, setCategoryInUpdate] = useState<Category>({
     name: '',
     name: '',
@@ -46,8 +45,8 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
     orderId: 0,
     orderId: 0,
     bookmarks: [],
     bookmarks: [],
     createdAt: new Date(),
     createdAt: new Date(),
-    updatedAt: new Date()
-  })
+    updatedAt: new Date(),
+  });
   const [bookmarkInUpdate, setBookmarkInUpdate] = useState<Bookmark>({
   const [bookmarkInUpdate, setBookmarkInUpdate] = useState<Bookmark>({
     name: '',
     name: '',
     url: '',
     url: '',
@@ -55,24 +54,24 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
     icon: '',
     icon: '',
     id: -1,
     id: -1,
     createdAt: new Date(),
     createdAt: new Date(),
-    updatedAt: new Date()
-  })
+    updatedAt: new Date(),
+  });
 
 
   useEffect(() => {
   useEffect(() => {
     if (categories.length === 0) {
     if (categories.length === 0) {
       getCategories();
       getCategories();
     }
     }
-  }, [getCategories])
+  }, [getCategories]);
 
 
   const toggleModal = (): void => {
   const toggleModal = (): void => {
     setModalIsOpen(!modalIsOpen);
     setModalIsOpen(!modalIsOpen);
-  }
+  };
 
 
   const addActionHandler = (contentType: ContentType) => {
   const addActionHandler = (contentType: ContentType) => {
     setFormContentType(contentType);
     setFormContentType(contentType);
     setIsInUpdate(false);
     setIsInUpdate(false);
     toggleModal();
     toggleModal();
-  }
+  };
 
 
   const editActionHandler = (contentType: ContentType) => {
   const editActionHandler = (contentType: ContentType) => {
     // We're in the edit mode and the same button was clicked - go back to list
     // We're in the edit mode and the same button was clicked - go back to list
@@ -82,11 +81,11 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
       setIsInEdit(true);
       setIsInEdit(true);
       setTableContentType(contentType);
       setTableContentType(contentType);
     }
     }
-  }
+  };
 
 
   const instanceOfCategory = (object: any): object is Category => {
   const instanceOfCategory = (object: any): object is Category => {
     return 'bookmarks' in object;
     return 'bookmarks' in object;
-  }
+  };
 
 
   const goToUpdateMode = (data: Category | Bookmark): void => {
   const goToUpdateMode = (data: Category | Bookmark): void => {
     setIsInUpdate(true);
     setIsInUpdate(true);
@@ -98,67 +97,76 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
       setBookmarkInUpdate(data);
       setBookmarkInUpdate(data);
     }
     }
     toggleModal();
     toggleModal();
-  }
+  };
 
 
   return (
   return (
     <Container>
     <Container>
       <Modal isOpen={modalIsOpen} setIsOpen={toggleModal}>
       <Modal isOpen={modalIsOpen} setIsOpen={toggleModal}>
-        {!isInUpdate
-          ? <BookmarkForm modalHandler={toggleModal} contentType={formContentType} />
-          : formContentType === ContentType.category
-            ? <BookmarkForm modalHandler={toggleModal} contentType={formContentType} category={categoryInUpdate} />
-            : <BookmarkForm modalHandler={toggleModal} contentType={formContentType} bookmark={bookmarkInUpdate} />
-        }
+        {!isInUpdate ? (
+          <BookmarkForm
+            modalHandler={toggleModal}
+            contentType={formContentType}
+          />
+        ) : formContentType === ContentType.category ? (
+          <BookmarkForm
+            modalHandler={toggleModal}
+            contentType={formContentType}
+            category={categoryInUpdate}
+          />
+        ) : (
+          <BookmarkForm
+            modalHandler={toggleModal}
+            contentType={formContentType}
+            bookmark={bookmarkInUpdate}
+          />
+        )}
       </Modal>
       </Modal>
 
 
-      <Headline
-        title='All Bookmarks'
-        subtitle={(<Link to='/'>Go back</Link>)}
-      />
-      
+      <Headline title="All Bookmarks" subtitle={<Link to="/">Go back</Link>} />
+
       <div className={classes.ActionsContainer}>
       <div className={classes.ActionsContainer}>
         <ActionButton
         <ActionButton
-          name='Add Category'
-          icon='mdiPlusBox'
+          name="Add Category"
+          icon="mdiPlusBox"
           handler={() => addActionHandler(ContentType.category)}
           handler={() => addActionHandler(ContentType.category)}
         />
         />
         <ActionButton
         <ActionButton
-          name='Add Bookmark'
-          icon='mdiPlusBox'
+          name="Add Bookmark"
+          icon="mdiPlusBox"
           handler={() => addActionHandler(ContentType.bookmark)}
           handler={() => addActionHandler(ContentType.bookmark)}
         />
         />
         <ActionButton
         <ActionButton
-          name='Edit Categories'
-          icon='mdiPencil'
+          name="Edit Categories"
+          icon="mdiPencil"
           handler={() => editActionHandler(ContentType.category)}
           handler={() => editActionHandler(ContentType.category)}
         />
         />
         <ActionButton
         <ActionButton
-          name='Edit Bookmarks'
-          icon='mdiPencil'
+          name="Edit Bookmarks"
+          icon="mdiPencil"
           handler={() => editActionHandler(ContentType.bookmark)}
           handler={() => editActionHandler(ContentType.bookmark)}
         />
         />
       </div>
       </div>
 
 
-      {loading
-        ? <Spinner />
-        : (!isInEdit
-          ? <BookmarkGrid categories={categories} />
-          : <BookmarkTable
-              contentType={tableContentType}
-              categories={categories}
-              updateHandler={goToUpdateMode}
-            />
-          )
-      }
+      {loading ? (
+        <Spinner />
+      ) : !isInEdit ? (
+        <BookmarkGrid categories={categories} searching />
+      ) : (
+        <BookmarkTable
+          contentType={tableContentType}
+          categories={categories}
+          updateHandler={goToUpdateMode}
+        />
+      )}
     </Container>
     </Container>
-  )
-}
+  );
+};
 
 
 const mapStateToProps = (state: GlobalState) => {
 const mapStateToProps = (state: GlobalState) => {
   return {
   return {
     loading: state.bookmark.loading,
     loading: state.bookmark.loading,
-    categories: state.bookmark.categories
-  }
-}
+    categories: state.bookmark.categories,
+  };
+};
 
 
-export default connect(mapStateToProps, { getCategories })(Bookmarks);
+export default connect(mapStateToProps, { getCategories })(Bookmarks);

+ 18 - 3
client/src/components/Home/Home.tsx

@@ -89,6 +89,18 @@ const Home = (props: ComponentProps): JSX.Element => {
     return () => clearInterval(interval);
     return () => clearInterval(interval);
   }, []);
   }, []);
 
 
+  // Search bookmarks
+  const searchBookmarks = (query: string): Category[] => {
+    const category = { ...categories[0] };
+    category.name = 'Search Results';
+    category.bookmarks = categories
+      .map(({ bookmarks }) => bookmarks)
+      .flat()
+      .filter(({ name }) => new RegExp(query, 'i').test(name));
+
+    return [category];
+  };
+
   return (
   return (
     <Container>
     <Container>
       {searchConfig('hideSearch', 0) !== 1 ? (
       {searchConfig('hideSearch', 0) !== 1 ? (
@@ -143,10 +155,13 @@ const Home = (props: ComponentProps): JSX.Element => {
             <Spinner />
             <Spinner />
           ) : (
           ) : (
             <BookmarkGrid
             <BookmarkGrid
-              categories={categories.filter(
-                (category: Category) => category.isPinned
-              )}
+              categories={
+                !localSearch
+                  ? categories.filter(({ isPinned }) => isPinned)
+                  : searchBookmarks(localSearch)
+              }
               totalCategories={categories.length}
               totalCategories={categories.length}
+              searching={!!localSearch}
             />
             />
           )}
           )}
         </Fragment>
         </Fragment>

+ 2 - 2
db.js

@@ -5,7 +5,7 @@ const logger = new Logger();
 const sequelize = new Sequelize({
 const sequelize = new Sequelize({
   dialect: 'sqlite',
   dialect: 'sqlite',
   storage: './data/db.sqlite',
   storage: './data/db.sqlite',
-  logging: false
+  logging: false,
 });
 });
 
 
 const connectDB = async () => {
 const connectDB = async () => {
@@ -28,5 +28,5 @@ const connectDB = async () => {
 
 
 module.exports = {
 module.exports = {
   connectDB,
   connectDB,
-  sequelize
+  sequelize,
 };
 };