From c5b779d7cd70ce35e7e377d0e20e33eed286c6d3 Mon Sep 17 00:00:00 2001 From: rayzhou-bit Date: Tue, 30 Apr 2024 00:49:55 -0700 Subject: [PATCH] filter and sort --- .../Dropdowns/ColorDropdown.jsx | 4 +- src/components/Card/LibraryTitle.jsx | 3 +- src/components/Card/Title.jsx | 3 +- src/components/Library/FilterBar.jsx | 66 ++++++++++ src/components/Library/SortBar.jsx | 46 +++++++ src/components/Library/hooks.js | 116 +++++++++++++----- src/components/Library/index.jsx | 31 +++-- src/components/Library/index.scss | 65 ++++++++++ 8 files changed, 287 insertions(+), 47 deletions(-) create mode 100644 src/components/Library/FilterBar.jsx create mode 100644 src/components/Library/SortBar.jsx diff --git a/src/components-shared/Dropdowns/ColorDropdown.jsx b/src/components-shared/Dropdowns/ColorDropdown.jsx index 4b087ba..7339204 100644 --- a/src/components-shared/Dropdowns/ColorDropdown.jsx +++ b/src/components-shared/Dropdowns/ColorDropdown.jsx @@ -7,10 +7,10 @@ import useOutsideClick from '../../utils/useOutsideClick'; export const ColorDropdown = ({ btnRef, - cardColor, isOpen, onClose, onUpdateColor, + selectedColor, }) => { const dropdownRef = useRef(); @@ -21,7 +21,7 @@ export const ColorDropdown = ({ let colorList = []; Object.values(CARD_COLOR_KEYS).forEach(color => { let className = 'item ' + color; - if (cardColor === color) { + if (selectedColor === color) { className += ' selected'; } colorList = [ diff --git a/src/components/Card/LibraryTitle.jsx b/src/components/Card/LibraryTitle.jsx index 09b4e03..f9c4cf7 100644 --- a/src/components/Card/LibraryTitle.jsx +++ b/src/components/Card/LibraryTitle.jsx @@ -78,12 +78,11 @@ const LibraryTitle = ({ + +
+ + +
+ + + + ); +}; + +export default FilterBar; diff --git a/src/components/Library/SortBar.jsx b/src/components/Library/SortBar.jsx new file mode 100644 index 0000000..319f1b1 --- /dev/null +++ b/src/components/Library/SortBar.jsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { SORT_OPTIONS } from './hooks'; + +import './index.scss'; + +const SortBar = ({ + sortOption, + setSortOption, +}) => { + + return ( +
+
+ Sort +
+
+ + + + +
+
+ ); +}; + +export default SortBar; \ No newline at end of file diff --git a/src/components/Library/hooks.js b/src/components/Library/hooks.js index 1cf860d..0b8c9b1 100644 --- a/src/components/Library/hooks.js +++ b/src/components/Library/hooks.js @@ -1,8 +1,10 @@ -import { useState } from 'react'; +import { useState, useRef } from 'react'; import { useSelector } from 'react-redux'; +import { CARD_COLOR_KEYS } from '../../styles/colors'; export const FILTER_OPTIONS = { all: 'all', + color: 'color', thisTab: 'thisTab', unsorted: 'unsorted', }; @@ -10,7 +12,6 @@ export const FILTER_OPTIONS = { export const SORT_OPTIONS = { abc: 'abc', zxy: 'zxy', - color: 'color', newest: 'newest', oldest: 'oldest', }; @@ -20,50 +21,109 @@ export const VIEW_OPTIONS = { expanded: 'expanded', }; +const hasSearch = (card, search) => { + const title = card?.title ?? ''; + if (title.toLowerCase().includes(search.toLowerCase())) { + return true; + } + const text = card?.content?.text ?? ''; + if (text.toLowerCase().includes(search.toLowerCase())) { + return true; + } + return false; +}; + +const hasFilter = (card, filter, color, tab, allTabs) => { + switch(filter) { + case FILTER_OPTIONS.thisTab: + return !!card?.views?.[tab]; + case FILTER_OPTIONS.all: + return true; + case FILTER_OPTIONS.color: + return CARD_COLOR_KEYS[color] === card?.color; + case FILTER_OPTIONS.unsorted: + const cardTabs = Object.keys(card?.views); + const intersection = allTabs.filter(tab => cardTabs.includes(tab)); + return intersection.length === 0; + } + return false; +}; + +const sortCards = (cards, sort, cardData) => { + switch(sort) { + case SORT_OPTIONS.abc: + return cards.sort((a, b) => { + const aTitle = cardData[a]?.title ?? ''; + const bTitle = cardData[b]?.title ?? ''; + return aTitle.localeCompare(bTitle); + }); + case SORT_OPTIONS.zxy: + return cards.sort((a, b) => { + const aTitle = cardData[a]?.title ?? ''; + const bTitle = cardData[b]?.title ?? ''; + return bTitle.localeCompare(aTitle); + + }); + case SORT_OPTIONS.newest: + return cards.sort((a, b) => { + const aTime = cardData[a]?.editedOn ?? 0; + const bTime = cardData[b]?.editedOn ?? 0; + return bTime - aTime; + }); + case SORT_OPTIONS.oldest: + return cards.sort((a, b) => { + const aTime = cardData[a]?.editedOn ?? 0; + const bTime = cardData[b]?.editedOn ?? 0; + return aTime - bTime; + }); + } +}; + export const useLibraryHooks = () => { const activeTab = useSelector(state => state.project.present.activeViewId); const tabOrder = useSelector(state => state.project.present.viewOrder); const cardCollection = useSelector(state => state.project.present.cards); - const [isOpen, setIsOpen] = useState(false); - const [searchString, setSearchString] = useState(''); - const [filterOption, setFilterOption] = useState(FILTER_OPTIONS.all); - const [sortOption, setSortOption] = useState(SORT_OPTIONS.abc); - const [viewOption, setViewOption] = useState(VIEW_OPTIONS.condensed); + const [ isOpen, setIsOpen ] = useState(false); + const [ searchString, setSearchString ] = useState(''); + const [ filterOption, setFilterOption ] = useState(FILTER_OPTIONS.all); + const [ filterColor, setFilterColor ] = useState(null); + const [ sortOption, setSortOption ] = useState(SORT_OPTIONS.abc); + const [ viewOption, setViewOption ] = useState(VIEW_OPTIONS.condensed); let libraryCards = []; - const search = searchString.toLowerCase(); for (let id in cardCollection) { - const title = cardCollection[id].title ?? ''; - const text = cardCollection[id].content?.text ?? ''; - if (title.toLowerCase().includes(search) || text.toLowerCase().includes(search)) { - switch (filterOption) { - case FILTER_OPTIONS.all: - libraryCards = [ ...libraryCards, id ]; - break; - case FILTER_OPTIONS.thisTab: - if (cardCollection[id].views?.[activeTab]) { - libraryCards = [ ...libraryCards, id ]; - } - break; - case FILTER_OPTIONS.unsorted: - const tabsOfCard = Object.keys(cardCollection[id].views); - const intersection = tabOrder.filter(tab => tabsOfCard.includes(tab)) - if (intersection.length === 0) { - libraryCards = [ ...libraryCards, id ]; - } - break; - } + const card = cardCollection[id]; + if (hasSearch(card, searchString) && hasFilter(card, filterOption, filterColor, activeTab, tabOrder)) { + libraryCards = [ ...libraryCards, id ]; } } + libraryCards = sortCards(libraryCards, sortOption, cardCollection); return { isOpen, toggleLibrary: () => setIsOpen(!isOpen), setSearchString, + filterOption, setFilterOption, + filterColor, + setFilterColor, + sortOption, setSortOption, + viewOption, setViewOption, libraryCards, }; }; + +export const useColorDropdownHooks = () => { + const [ isColorDropdownOpen, setIsColorDropdownOpen ] = useState(false); + const colorDropdownBtnRef = useRef(); + + return { + colorDropdownBtnRef, + isColorDropdownOpen, + openColorDropdown: () => setIsColorDropdownOpen(!isColorDropdownOpen), + closeColorDropdown: () => setIsColorDropdownOpen(false), + }; +}; diff --git a/src/components/Library/index.jsx b/src/components/Library/index.jsx index 8ef413c..b421b0f 100644 --- a/src/components/Library/index.jsx +++ b/src/components/Library/index.jsx @@ -1,5 +1,7 @@ import React from 'react'; +import FilterBar from './FilterBar'; +import SortBar from './SortBar'; import LibraryCard from '../Card/LibraryCard'; import LibrarySearch from './LibrarySearch'; @@ -13,36 +15,39 @@ const Library = () => { isOpen, toggleLibrary, setSearchString, + filterOption, setFilterOption, + filterColor, + setFilterColor, + sortOption, setSortOption, + viewOption, setViewOption, libraryCards, } = useLibraryHooks(); - let cardComponents = []; - for (let id in libraryCards) { - cardComponents = [ - ...cardComponents, - , - ]; - } + const cardComponents = libraryCards.map(id => ); return (
- {/* TODO remove LibrarySearch and expand out its functionality to the following. Make changes to the hooks file to change filtering and sorting Change names of components if need be */} {/* */} - {/* */} - {/* */} - {/* */} - {/*
+ + + {/* */} +
{cardComponents} -
*/} +
+ +