Skip to content

Commit

Permalink
Merge pull request #6 from NosatskyiK/task/05-hooks
Browse files Browse the repository at this point in the history
added sorting, filters and pagination
  • Loading branch information
vadym-zinchenko-moc authored Jun 7, 2024
2 parents a211374 + 693c22c commit 92e6461
Show file tree
Hide file tree
Showing 7 changed files with 421 additions and 62 deletions.
10 changes: 9 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useState } from 'react';
import { clsx } from 'clsx';

import { AboutMe } from '@/components/aboutMe/AboutMe.component.tsx';
import { FiltersBar } from '@/components/filtersBar/FiltersBar.component.tsx';
import { FooterComponent } from '@/components/footer/Footer.component.tsx';
import { HeaderComponent } from '@/components/header/Header.component.tsx';
import { ProductList } from '@/components/productList/ProductList.component.tsx';
Expand All @@ -13,14 +14,21 @@ import './App.css';
function App() {
const [activePage, setActivePage] = useState('about');
const [theme, setTheme] = useState('light');
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
const [sortCriteria, setSortCriteria] = useState('Price (High - Low)');
const themeClass = clsx(`${theme}Theme`);

return (
<div className={themeClass}>
<HeaderComponent changeTheme={setTheme} activeTheme={theme} onPageChange={setActivePage} activePage={activePage} />
<>
{activePage === 'about' && <AboutMe />}
{activePage === 'products' && <ProductList products={products} />}
{activePage === 'products' && (
<>
<FiltersBar onCategoryChange={setSelectedCategory} onSortChange={setSortCriteria} />
<ProductList products={products} selectedCategory={selectedCategory} sortCriteria={sortCriteria} />
</>
)}
</>
<FooterComponent />
</div>
Expand Down
17 changes: 12 additions & 5 deletions src/components/filtersBar/FiltersBar.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import React from 'react';

import searchIcon from '@/assets/img/searchIcon.svg?url';
import { SortList } from '@/components/sortList/SortList.components.tsx';
import type { FiltersBarProps } from '@/interface/interfaceProductFilters.ts';

import styles from './filtersBar.module.css';

export const FiltersBar = () => (
export const FiltersBar: React.FC<FiltersBarProps> = ({ onCategoryChange, onSortChange }) => (
<section className={styles.filtersBar}>
<div className={styles.searchBar}>
<input className={styles.searchInput} type="text" placeholder="Search..." />
Expand All @@ -14,10 +15,16 @@ export const FiltersBar = () => (
</button>
</div>
<div className={styles.filterButtons}>
<button className={styles.filterButton}>Electronics</button>
<button className={styles.filterButton}>Shoes</button>
<button className={styles.filterButton}>Clothes</button>
<button className={styles.filterButton} onClick={() => onCategoryChange('Electronics')}>
Electronics
</button>
<button className={styles.filterButton} onClick={() => onCategoryChange('Shoes')}>
Shoes
</button>
<button className={styles.filterButton} onClick={() => onCategoryChange('Clothes')}>
Clothes
</button>
</div>
<SortList />
<SortList onSortChange={onSortChange} />
</section>
);
77 changes: 64 additions & 13 deletions src/components/productList/ProductList.component.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,69 @@
import React from 'react';
import React, { useState } from 'react';

import { FiltersBar } from '@/components/filtersBar/FiltersBar.component.tsx';
import { ProductCard } from '@/components/productCard/ProductCard.component.tsx';
import type { Product } from '@/interface/interfaceProductCategory.ts';
import type { ProductListProps } from '@/interface/interfaceProductFilters.ts';

import styles from './productList.module.css';

export const ProductList: React.FC<{ products: Product[] }> = ({ products }) => (
<>
<FiltersBar />
<section className={styles.productList}>
{products.map((product, index) => (
<ProductCard key={index} product={product} />
))}
</section>
</>
);
export const ProductList: React.FC<ProductListProps> = ({ products, selectedCategory, sortCriteria }) => {
const [currentPage, setCurrentPage] = useState(1);
const itemsPerPage = 8;

const filteredProducts = selectedCategory ? products.filter((product) => product.category.name === selectedCategory) : products;

const sortedProducts = [...filteredProducts].sort((a, b) => {
switch (sortCriteria) {
case 'Price (High - Low)': {
return b.price - a.price;
}
case 'Price (Low - High)': {
return a.price - b.price;
}
case 'Newest': {
return new Date(b.creationAt).getTime() - new Date(a.creationAt).getTime();
}
case 'Oldest': {
return new Date(a.creationAt).getTime() - new Date(b.creationAt).getTime();
}
default: {
return 0;
}
}
});

const totalPages = Math.ceil(sortedProducts.length / itemsPerPage);
const indexOfLastItem = currentPage * itemsPerPage;
const indexOfFirstItem = indexOfLastItem - itemsPerPage;
const currentItems = sortedProducts.slice(indexOfFirstItem, indexOfLastItem);

return (
<>
<section className={styles.productList}>
{currentItems.map((product, index) => (
<ProductCard key={index} product={product} />
))}
</section>
<div className={styles.pagination}>
<button
className={styles.paginationButton}
onClick={() => currentPage < totalPages && setCurrentPage(currentPage - 1)}
disabled={currentPage === 1}
>
&#60;
</button>
{Array.from({ length: totalPages }, (_, index) => (
<button className={styles.paginationButton} key={index} onClick={() => setCurrentPage(index + 1)}>
{index + 1}
</button>
))}
<button
className={styles.paginationButton}
onClick={() => currentPage < totalPages && setCurrentPage(currentPage + 1)}
disabled={currentPage === totalPages}
>
&#62;
</button>
</div>
</>
);
};
27 changes: 25 additions & 2 deletions src/components/productList/productList.module.css
Original file line number Diff line number Diff line change
@@ -1,11 +1,34 @@
.productList {
.productList, .pagination {
display: flex;
margin: 60px;
}

.productList {
justify-content: space-around;
flex-wrap: wrap;
margin: 60px;
gap: 25px;
}

.pagination {
justify-content: center;
gap: 5px;
}

.paginationButton {
width: 32px;
height: 32px;
border-radius: 8px;
border: 1px solid var(--color-border-button);
background-color: var(--bg-primary);
cursor: pointer;
color: var(--txt-secondary);
}

.paginationButton:hover {
background-color: var(--background-button);
color: #FFF;
}

@media (max-width: 768px) {

.productList {
Expand Down
19 changes: 10 additions & 9 deletions src/components/sortList/SortList.components.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import React, { useState } from 'react';

import type { SortListProps } from '@/interface/interfaceProductFilters.ts';

import styles from './sortList.module.css';

export const SortList = () => {
export const SortList: React.FC<SortListProps> = ({ onSortChange }) => {
const [willShowList, setShowList] = useState(false);
const [selectedValue, setSelectedValue] = useState('Price (High - Low)');

const listItems = ['Price (High - Low)', 'Price (Low - High)', 'Newest', 'Oldest'];

const handleSortChange = (item: string) => {
setSelectedValue(item);
setShowList(false);
onSortChange(item);
};

return (
<div className={styles.sort}>
<span className={styles.sortLabel}>Sort by:</span>
Expand All @@ -18,14 +26,7 @@ export const SortList = () => {
{willShowList && (
<ul className={styles.listBody}>
{listItems.map((item) => (
<li
key={item}
className={styles.listItem}
onClick={() => {
setSelectedValue(item);
setShowList(!willShowList);
}}
>
<li key={item} className={styles.listItem} onClick={() => handleSortChange(item)}>
{item}
</li>
))}
Expand Down
Loading

0 comments on commit 92e6461

Please sign in to comment.