From 62da62d5b9274c12f8f2eee50fb2bb504f9687a1 Mon Sep 17 00:00:00 2001 From: Olena Nikishyna Date: Wed, 25 Sep 2024 14:46:40 +0300 Subject: [PATCH 1/3] added searc bar, fixed closing dropdowns on side click --- src/components/Catalog/Catalog.module.scss | 18 ++++ src/components/Catalog/Catalog.tsx | 102 +++++++++++++----- src/components/Dropdown/Dropdown.module.scss | 5 +- src/components/Dropdown/Dropdown.tsx | 11 +- .../ItemsPerPageDropdown.module.scss | 5 +- .../ItemsPerPageDropdown.tsx | 9 +- .../SearchBar/SearchBar.module.scss | 63 +++++++++++ src/components/SearchBar/SearchBar.tsx | 39 +++++++ src/components/SearchBar/index.ts | 1 + 9 files changed, 222 insertions(+), 31 deletions(-) create mode 100644 src/components/SearchBar/SearchBar.module.scss create mode 100644 src/components/SearchBar/SearchBar.tsx create mode 100644 src/components/SearchBar/index.ts diff --git a/src/components/Catalog/Catalog.module.scss b/src/components/Catalog/Catalog.module.scss index 412392b..d365eba 100644 --- a/src/components/Catalog/Catalog.module.scss +++ b/src/components/Catalog/Catalog.module.scss @@ -138,3 +138,21 @@ } } } + +.phonesDropdown { + display: flex; + +} + +.noResults{ + margin-top: 20px; +} + +.filtration { + display: flex; + flex-direction: column; + + @include onTablet { + flex-direction: row; + } +} \ No newline at end of file diff --git a/src/components/Catalog/Catalog.tsx b/src/components/Catalog/Catalog.tsx index e48db33..242c611 100644 --- a/src/components/Catalog/Catalog.tsx +++ b/src/components/Catalog/Catalog.tsx @@ -6,6 +6,7 @@ import { ItemsPerPageOption, SortOption } from '../../utils/types/SortOption'; import { Dropdown } from '../Dropdown'; import { ItemsPerPageDropdown } from '../ItemsPerPageDropdown'; import { useLocation, useNavigate } from 'react-router-dom'; +import { SearchBar } from '../SearchBar/SearchBar'; import { sortProducts } from '../../utils/helpers/sortProducts'; import { Breadcrumbs } from '../Breadcrumbs'; @@ -21,6 +22,7 @@ export const Catalog: React.FC = ({ items, title, isFiltered }) => { const [currentPage, setCurrentPage] = useState(1); const [sortOption, setSortOption] = useState('alphabetical'); const [itemsPerPage, setItemsPerPage] = useState(16); + const [searchQuery, setSearchQuery] = useState(''); useEffect(() => { const searchParams = new URLSearchParams(location.search); @@ -48,22 +50,35 @@ export const Catalog: React.FC = ({ items, title, isFiltered }) => { } }, [location.search]); - const sortedItems = useMemo(() => { - return sortProducts(items, sortOption); - }, [items, sortOption]); + const filteredItems = useMemo(() => { + let filtered = sortProducts(items, sortOption); + if (searchQuery.trim() !== '') { + filtered = filtered.filter(item => + item.name.toLowerCase().includes(searchQuery.toLowerCase()), + ); + } + return filtered; + }, [items, sortOption, searchQuery]); const paginatedItems = useMemo(() => { + let filtered = filteredItems; + if (searchQuery.trim() !== '') { + filtered = filteredItems.filter(item => + item.name.toLowerCase().includes(searchQuery.toLowerCase()), + ); + } + if (itemsPerPage === 'all') { - return sortedItems; + return filtered; } const indexOfLastItem = currentPage * itemsPerPage; const indexOfFirstItem = indexOfLastItem - itemsPerPage; - return sortedItems.slice(indexOfFirstItem, indexOfLastItem); - }, [sortedItems, currentPage, itemsPerPage]); + return filtered.slice(indexOfFirstItem, indexOfLastItem); + }, [filteredItems, currentPage, itemsPerPage, searchQuery]); const totalPages = - itemsPerPage === 'all' ? 1 : Math.ceil(sortedItems.length / itemsPerPage); + itemsPerPage === 'all' ? 1 : Math.ceil(filteredItems.length / itemsPerPage); const handlePrevPage = () => { if (currentPage > 1) { @@ -79,15 +94,26 @@ export const Catalog: React.FC = ({ items, title, isFiltered }) => { const paginate = (pageNumber: number) => setCurrentPage(pageNumber); - const updateURL = (sort: SortOption, perPage: ItemsPerPageOption) => { + const updateURL = ( + sort: SortOption, + perPage: ItemsPerPageOption, + searchQuery: string, + ) => { const searchParams = new URLSearchParams(location.search); searchParams.set('sort', sort); - if (perPage === 8) { + if (perPage === 16) { searchParams.delete('perPage'); } else { searchParams.set('perPage', perPage.toString()); } + + if (searchQuery.trim() !== '') { + searchParams.set('q', searchQuery); + } else { + searchParams.delete('q'); + } + navigate(`${location.pathname}?${searchParams.toString()}`, { replace: true, }); @@ -96,13 +122,19 @@ export const Catalog: React.FC = ({ items, title, isFiltered }) => { const handleSort = (option: SortOption) => { setSortOption(option); setCurrentPage(1); - updateURL(option, itemsPerPage); + updateURL(option, itemsPerPage, searchQuery); }; const handleItemsPerPageChange = (option: ItemsPerPageOption) => { setItemsPerPage(option); setCurrentPage(1); - updateURL(sortOption, option); + updateURL(sortOption, option, searchQuery); + }; + + const handleSearch = (query: string) => { + setSearchQuery(query); + setCurrentPage(1); + updateURL(sortOption, itemsPerPage, query); }; return ( @@ -110,25 +142,43 @@ export const Catalog: React.FC = ({ items, title, isFiltered }) => {
{title}
-
{items.length} models
+
+ {filteredItems.length} models +
{isFiltered && ( -
- - +
+
+ + +
+
)} -
- {paginatedItems.map((item: UnionProduct) => ( -
- -
- ))} -
- {itemsPerPage !== 'all' && ( + {paginatedItems.length === 0 && ( +
+

No results found

+

Try searching for something else.

+
+ )} + + {paginatedItems.length > 0 && ( +
+ {paginatedItems.map((item: UnionProduct) => ( +
+ +
+ ))} +
+ )} + + {paginatedItems.length > 0 && itemsPerPage !== 'all' && (
+
+ ); +}; diff --git a/src/components/SearchBar/index.ts b/src/components/SearchBar/index.ts new file mode 100644 index 0000000..3d7e42e --- /dev/null +++ b/src/components/SearchBar/index.ts @@ -0,0 +1 @@ +export * from './SearchBar'; From da688df649e3c92f2ac703bdbd19c2378df71fd8 Mon Sep 17 00:00:00 2001 From: Olena Nikishyna Date: Wed, 25 Sep 2024 15:41:43 +0300 Subject: [PATCH 2/3] merged develop --- .../ItemsPerPageDropdown/ItemsPerPageDropdown.module.scss | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/ItemsPerPageDropdown/ItemsPerPageDropdown.module.scss b/src/components/ItemsPerPageDropdown/ItemsPerPageDropdown.module.scss index 9779db7..a8f84c9 100644 --- a/src/components/ItemsPerPageDropdown/ItemsPerPageDropdown.module.scss +++ b/src/components/ItemsPerPageDropdown/ItemsPerPageDropdown.module.scss @@ -105,5 +105,4 @@ color: $primary-color; } } - } - \ No newline at end of file + } \ No newline at end of file From 27b98b373d1157786fb90be8eda0df4198287dde Mon Sep 17 00:00:00 2001 From: Olena Nikishyna Date: Wed, 25 Sep 2024 15:54:35 +0300 Subject: [PATCH 3/3] changed function --- src/utils/helpers/sortProducts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/helpers/sortProducts.ts b/src/utils/helpers/sortProducts.ts index 240c0cd..8dce2fe 100644 --- a/src/utils/helpers/sortProducts.ts +++ b/src/utils/helpers/sortProducts.ts @@ -14,7 +14,7 @@ export function sortProducts(items: UnionProduct[], sortOption: SortOption) { return sorted.sort((a, b) => b.priceDiscount - a.priceDiscount); case 'newest': - return sorted.sort((a, b) => b.year - a.year); + return sorted.sort((a, b) => b.name.localeCompare(a.name)); default: return sorted;