Skip to content

Commit

Permalink
[#3641] Added filtering to catalog view (#3781)
Browse files Browse the repository at this point in the history
  • Loading branch information
Thorsten authored Oct 5, 2022
1 parent 3a97ffd commit 0f7b327
Show file tree
Hide file tree
Showing 12 changed files with 462 additions and 35 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
@import 'assets/scss/fonts.scss';
@import 'assets/scss/colors.scss';

.container {
display: flex;
align-items: center;
}

.iconContainer {
display: flex;
align-items: center;
justify-content: space-between;
svg {
margin-left: 16px;
color: var(--color-text-gray);

&:hover {
cursor: pointer;
color: var(--color-airy-blue);
}
}
.filterIcon {
transition: background 0.5s ease;
color: var(--color-background-white);
margin-left: 16px;
background: var(--color-airy-logo-blue);
border-radius: 24px;
}
}

.searchField {
width: 200px;
background: var(--color-background-white);
border: 1px solid var(--color-airy-blue);
border-radius: 4px;

svg {
color: black;
}
}

@keyframes animateFilterModalIn {
0% {
transform: translateX(200px);
opacity: 0;
}

100% {
transform: translateX(0px);
opacity: 1;
}
}

@keyframes animateFilterModalOut {
0% {
transform: translateX(0px);
opacity: 1;
}
100% {
transform: translateX(200px);
opacity: 0;
}
}

.filterModal {
position: absolute;
top: 170px;
right: 54px;
}

.filterModalAnimIn {
animation: animateFilterModalIn 500ms ease;
}
.filterModalAnimOut {
animation: animateFilterModalOut 500ms ease;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, {Dispatch, SetStateAction, useCallback, useEffect, useState} from 'react';
import {ReactComponent as SearchIcon} from 'assets/images/icons/search.svg';
import {ReactComponent as FilterIcon} from 'assets/images/icons/filterAlt.svg';
import styles from './CatalogSearchBar.module.scss';
import {ListenOutsideClick, SearchField} from 'components';
import {useTranslation} from 'react-i18next';
import {FilterCatalogModal, FilterTypes} from './FilterCatalogModal/FilterCatalogModal';
import {useAnimation} from 'render';

type CatalogSearchBarProps = {
currentFilter: FilterTypes;
setCurrentFilter: Dispatch<SetStateAction<FilterTypes>>;
setQuery: Dispatch<SetStateAction<string>>;
};

export const CatalogSearchBar = (props: CatalogSearchBarProps) => {
const {t} = useTranslation();
const [query, setQuery] = useState('');
const [currentFilter, setCurrentFilter] = useState(props.currentFilter);
const [showSearchField, setShowingSearchField] = useState(false);
const [showFilter, setShowFilter] = useState(false);
const [animationAction, setAnimationAction] = useState(false);

const toggleShowFilter = useCallback(() => {
useAnimation(showFilter, setShowFilter, setAnimationAction, 500);
}, [showFilter, setShowFilter]);

useEffect(() => {
props.setCurrentFilter(currentFilter);
}, [currentFilter]);

const handleSearchClick = () => {
setShowingSearchField(true);
};

return (
<div className={styles.container}>
<div className={styles.iconContainer}>
{showSearchField ? (
<SearchField
autoFocus
className={styles.searchField}
placeholder={t('searchByNamePlaceholder')}
value={query}
setValue={(value: string) => {
setQuery(value), props.setQuery(value);
}}
/>
) : (
<SearchIcon height={20} width={20} className={styles.searchIcon} onClick={handleSearchClick} />
)}
<FilterIcon
height={24}
width={24}
className={currentFilter !== FilterTypes.all ? styles.filterIcon : ''}
onClick={toggleShowFilter}
/>
<div
className={`${styles.filterModal} ${animationAction ? styles.filterModalAnimIn : styles.filterModalAnimOut}`}
>
{showFilter && (
<ListenOutsideClick onOuterClick={showFilter && toggleShowFilter}>
<FilterCatalogModal
currentFilter={currentFilter}
setCurrentFilter={setCurrentFilter}
setShowFilter={toggleShowFilter}
/>
</ListenOutsideClick>
)}
</div>
</div>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
@import 'assets/scss/fonts.scss';
@import 'assets/scss/colors.scss';

.container {
display: flex;
flex-direction: column;
align-items: center;
min-width: 520px;
min-height: 300px;
background: var(--color-background-white);
border: 1px solid var(--color-disabled-gray);
border-radius: 10px;
}

.titleContainer {
display: flex;
justify-content: space-between;
width: 90%;
margin: 21px 0px;
color: var(--color-text-contrast);
text-transform: capitalize;

h1 {
@include font-base;
font-weight: bold;
}
}

.closeIcon {
svg {
color: var(--color-text-contrast);
margin-left: 8px;
}
&:hover {
cursor: pointer;
color: var(--color-airy-blue);
svg {
color: var(--color-airy-blue);
}
}
}

.filterTypes {
display: flex;
button {
@include font-base;
border: 1px solid #1578d4;
border-radius: 100px;
background: transparent;
color: var(--color-airy-blue);
margin: 0 12px;
&:hover {
background: var(--color-background-blue);
transition: background 0.5s ease;
}
}
.activeButton {
background: var(--color-airy-blue);
color: var(--color-background-white);
&:hover {
background: var(--color-airy-blue);
color: var(--color-background-white);
}
}
}

.filterTypesDarkMode {
@extend .filterTypes;
button {
border: 1px solid white;
color: white;
}

.activeButton {
background: var(--color-airy-blue);
border: 1px solid var(--color-airy-blue);
color: white;
&:hover {
color: white;
}
}
}

.line {
height: 1px;
width: 100%;
background-color: var(--color-text-gray);
margin-top: 109px;
}

.actionButtons {
display: flex;
align-items: center;
margin: 16px 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import {Button} from 'components';
import React, {Dispatch, SetStateAction, useState} from 'react';
import {useTranslation} from 'react-i18next';
import {ReactComponent as CloseIcon} from 'assets/images/icons/close.svg';
import styles from './FilterCatalogModal.module.scss';

export enum FilterTypes {
all = 'all',
installed = 'installed',
comingSoon = 'comingSoon',
notInstalled = 'notInstalled',
}

type FilterCatalogModalProps = {
currentFilter: FilterTypes;
setCurrentFilter: Dispatch<SetStateAction<FilterTypes>>;
setShowFilter: Dispatch<SetStateAction<boolean>>;
};

export const FilterCatalogModal = (props: FilterCatalogModalProps) => {
const [currentFilter, setCurrentFilter] = useState(props.currentFilter || FilterTypes.all);
const {t} = useTranslation();
const darkModeOn = localStorage.getItem('theme') === 'dark';

const applyFilter = () => {
props.setCurrentFilter(currentFilter);
props.setShowFilter(false);
localStorage.setItem('catalogCurrentTypeFilter', currentFilter);
};

const clearFilter = () => {
setCurrentFilter(FilterTypes.all);
props.setCurrentFilter(FilterTypes.all);
localStorage.setItem('catalogCurrentTypeFilter', currentFilter);
};

return (
<div className={styles.container}>
<div className={styles.titleContainer}>
<h1>{t('searchByType')}</h1>
<CloseIcon className={styles.closeIcon} height={12} width={12} onClick={() => props.setShowFilter(false)} />
</div>
<div className={darkModeOn ? styles.filterTypesDarkMode : styles.filterTypes}>
<Button
className={currentFilter === FilterTypes.all ? styles.activeButton : ''}
onClick={() => setCurrentFilter(FilterTypes.all)}
>
{t('all')}
</Button>
<Button
className={currentFilter === FilterTypes.installed && styles.activeButton}
onClick={() => setCurrentFilter(FilterTypes.installed)}
>
{t('installed')}
</Button>
<Button
className={currentFilter === FilterTypes.comingSoon && styles.activeButton}
onClick={() => setCurrentFilter(FilterTypes.comingSoon)}
>
{t('comingSoon')}
</Button>
<Button
className={currentFilter === FilterTypes.notInstalled && styles.activeButton}
onClick={() => setCurrentFilter(FilterTypes.notInstalled)}
>
{t('notInstalled')}
</Button>
</div>
<div className={styles.line} />
<div className={styles.actionButtons}>
<Button onClick={clearFilter} styleVariant="text" className={styles.clearAllButton}>
{t('clearAll')}
</Button>
<Button onClick={applyFilter}>{t('apply')}</Button>
</div>
</div>
);
};
18 changes: 18 additions & 0 deletions frontend/control-center/src/pages/Catalog/index.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
width: 100%;
}

.headlineSearchBarContainer {
display: flex;
justify-content: space-between;
align-items: center;
}

.catalogListContainer {
display: flex;
flex-wrap: wrap;
Expand All @@ -25,6 +31,18 @@
color: var(--color-text-contrast);
}

.notFoundContainer {
display: flex;
flex-direction: column;
h1 {
@include font-l;
font-weight: bold;
}
span {
@include font-m;
}
}

.notificationAnimation {
display: flex;
align-items: center;
Expand Down
Loading

0 comments on commit 0f7b327

Please sign in to comment.