Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

filter and sort #46

Merged
merged 1 commit into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/components-shared/Dropdowns/ColorDropdown.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import useOutsideClick from '../../utils/useOutsideClick';

export const ColorDropdown = ({
btnRef,
cardColor,
isOpen,
onClose,
onUpdateColor,
selectedColor,
}) => {
const dropdownRef = useRef();

Expand All @@ -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 = [
Expand Down
3 changes: 1 addition & 2 deletions src/components/Card/LibraryTitle.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,11 @@ const LibraryTitle = ({
<img src={isLightColor ? OpenColorBlackIcon : OpenColorWhiteIcon} />
</button>
<ColorDropdown
cardId={cardId}
btnRef={colorDropdownBtnRef}
cardColor={color}
isOpen={isColorDropdownOpen}
onClose={closeColorDropdown}
onUpdateColor={updateColor}
selectedColor={color}
/>
<button
className='dropdown-btn'
Expand Down
3 changes: 1 addition & 2 deletions src/components/Card/Title.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,11 @@ const Title = ({
<img src={isLightColor ? OpenColorBlackIcon : OpenColorWhiteIcon} />
</button>
<ColorDropdown
cardId={cardId}
btnRef={colorDropdownBtnRef}
cardColor={color}
isOpen={isColorDropdownOpen}
onClose={closeColorDropdown}
onUpdateColor={updateColor}
selectedColor={color}
/>
<button
className='dropdown-btn'
Expand Down
66 changes: 66 additions & 0 deletions src/components/Library/FilterBar.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react';
import ColorDropdown from '../../components-shared/Dropdowns/ColorDropdown';
import { FILTER_OPTIONS, useColorDropdownHooks } from './hooks';
import './index.scss';
import '../../styles/colors.scss';
import { CARD_COLOR_KEYS } from '../../styles/colors';

const FilterBar = ({
filterOption,
setFilterOption,
filterColor,
setFilterColor,
}) => {
const {
colorDropdownBtnRef,
isColorDropdownOpen,
openColorDropdown,
closeColorDropdown,
} = useColorDropdownHooks();

return (
<div className='selection-row'>
<div className='title'>
<span>Filter</span>
</div>
<div className='selections'>
<button
className={`option ${filterOption === FILTER_OPTIONS.thisTab ? 'selected' : null}`}
onClick={() => setFilterOption(FILTER_OPTIONS.thisTab)}
>
<span>Cards in this Tab</span>
</button>
<button
className={`option ${filterOption === FILTER_OPTIONS.all ? 'selected' : null}`}
onClick={() => setFilterOption(FILTER_OPTIONS.all)}
>
<span>All Cards</span>
</button>
<div className='color-selection'>
<button
className={`option ${filterOption === FILTER_OPTIONS.color ? 'selected' : null}`}
onClick={() => setFilterOption(FILTER_OPTIONS.color)}
>
<span>Color</span>
<button className={`color-display ${CARD_COLOR_KEYS[filterColor] ?? '#F4F4F4'}`} onClick={() => openColorDropdown()} ref={colorDropdownBtnRef} />
</button>
<ColorDropdown
btnRef={colorDropdownBtnRef}
selectedColor={filterColor}
isOpen={isColorDropdownOpen}
onClose={closeColorDropdown}
onUpdateColor={setFilterColor}
/>
</div>
<button
className={`option ${filterOption === FILTER_OPTIONS.unsorted ? 'selected' : null}`}
onClick={() => setFilterOption(FILTER_OPTIONS.unsorted)}
>
<span>Unsorted</span>
</button>
</div>
</div>
);
};

export default FilterBar;
46 changes: 46 additions & 0 deletions src/components/Library/SortBar.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import { SORT_OPTIONS } from './hooks';

import './index.scss';

const SortBar = ({
sortOption,
setSortOption,
}) => {

return (
<div className='selection-row'>
<div className='title'>
<span>Sort</span>
</div>
<div className='selections'>
<button
className={`option ${sortOption === SORT_OPTIONS.abc ? 'selected' : null}`}
onClick={() => setSortOption(SORT_OPTIONS.abc)}
>
<span>ABC</span>
</button>
<button
className={`option ${sortOption === SORT_OPTIONS.zxy ? 'selected' : null}`}
onClick={() => setSortOption(SORT_OPTIONS.zxy)}
>
<span>ZXY</span>
</button>
<button
className={`option ${sortOption === SORT_OPTIONS.newest ? 'selected' : null}`}
onClick={() => setSortOption(SORT_OPTIONS.newest)}
>
<span>Newest</span>
</button>
<button
className={`option ${sortOption === SORT_OPTIONS.oldest ? 'selected' : null}`}
onClick={() => setSortOption(SORT_OPTIONS.oldest)}
>
<span>Oldest</span>
</button>
</div>
</div>
);
};

export default SortBar;
116 changes: 88 additions & 28 deletions src/components/Library/hooks.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
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',
};

export const SORT_OPTIONS = {
abc: 'abc',
zxy: 'zxy',
color: 'color',
newest: 'newest',
oldest: 'oldest',
};
Expand All @@ -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),
};
};
31 changes: 18 additions & 13 deletions src/components/Library/index.jsx
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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,
<LibraryCard key={id} cardId={id} />,
];
}
const cardComponents = libraryCards.map(id => <LibraryCard key={id} cardId={id} />);

return (
<div className={`library ${isOpen ? 'open': 'close'}`}>
<div className='library-panel'>
<LibrarySearch />
{/*
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
*/}
{/* <SearchBar setSearchString={setSearchString} /> */}
{/* <FilterBar setFilterOption={setFilterOption} /> */}
{/* <SortBar setSortOption={setSortOption} /> */}
{/* <ViewBar setViewOption={setViewOption} /> */}
{/* <div className='library-card-container'>
<FilterBar
filterOption={filterOption} setFilterOption={setFilterOption}
filterColor={filterColor} setFilterColor={setFilterColor}
/>
<SortBar sortOption={sortOption} setSortOption={setSortOption} />
{/* <ViewBar viewOption={viewOption} setViewOption={setViewOption} /> */}
<div className='library-card-container'>
{cardComponents}
</div> */}
</div>

<LibrarySearch />
</div>
<button className='library-btn' onClick={toggleLibrary}>
<img src={LibraryIcon} alt='Library' />
Expand Down
Loading
Loading