Skip to content

Commit

Permalink
add: search, lazyLoad, backBtn
Browse files Browse the repository at this point in the history
  • Loading branch information
AM1007 committed Mar 1, 2024
1 parent 0e82db2 commit 1645cc5
Show file tree
Hide file tree
Showing 13 changed files with 146 additions and 29 deletions.
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"axios": "^0.27.2",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-icons": "^5.0.1",
"react-router-dom": "^6.22.1",
"react-scripts": "5.0.1",
"react-tabs": "^5.1.0",
Expand Down
22 changes: 13 additions & 9 deletions src/components/App/App.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { Routes, Route } from 'react-router-dom';
import About from 'pages/About';
import Products from 'pages/Products';
import ProductDetails from 'pages/ProductDetails';
import NotFound from 'pages/NotFound';
import Mission from 'pages/Mission';
import Team from 'pages/Team';
import Reviews from 'pages/Reviews';
import Home from 'pages/Home';
import { lazy } from 'react';
import Sharedlayout from 'components/SharedLayout/SharedLayout';
import NotFound from 'pages/NotFound';

export const App = () => {
const About = lazy(() => import('pages/About'));
const Home = lazy(() => import('pages/Home'));
const ProductDetails = lazy(() => import('pages/ProductDetails'));
const Products = lazy(() => import('pages/Products'));
const Mission = lazy(() => import('pages/Mission'));
const Team = lazy(() => import('pages/Team'));
const Reviews = lazy(() => import('pages/Reviews'));

const App = () => {
return (
<Routes>
<Route path="/" element={<Sharedlayout />}>
Expand All @@ -26,3 +28,5 @@ export const App = () => {
</Routes>
);
};

export default App;
29 changes: 29 additions & 0 deletions src/components/BackLink/BackLink.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { HiArrowLeft } from 'react-icons/hi';
import { Link } from 'react-router-dom';
import styled from 'styled-components';

const StyledLink = styled(Link)`
display: inline-flex;
align-items: center;
gap: 4px;
padding: 8px 0;
color: black;
text-decoration: none;
font-weight: 500;
text-transform: uppercase;
&:hover {
color: orangered;
}
`;

const BackLink = ({ to, children }) => {
return (
<StyledLink to={to}>
<HiArrowLeft size="24" />
{children}
</StyledLink>
);
};

export default BackLink;
10 changes: 7 additions & 3 deletions src/components/ProductList/ProductList.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { Link } from 'react-router-dom';
import { Link, useLocation } from 'react-router-dom';
import { Container, CardWrapper, ProductName } from './ProductList.styled';

export const ProductList = ({ products }) => {
const ProductList = ({ products }) => {
const location = useLocation();

return (
<Container>
{products.map(product => (
<CardWrapper key={product.id}>
<Link to={`${product.id}`}>
<Link to={`${product.id}`} state={{ from: location }}>
<img src="https://via.placeholder.com/200x100" alt="" />
<ProductName>{product.name}</ProductName>
</Link>
Expand All @@ -15,3 +17,5 @@ export const ProductList = ({ products }) => {
</Container>
);
};

export default ProductList;
16 changes: 16 additions & 0 deletions src/components/SearchBox/SearchBox.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Icon, Input, Wrapper } from './SearchBox.styled';

const SearchBox = ({ value, onChange }) => {
return (
<Wrapper>
<Icon />
<Input
type="text"
value={value}
onChange={e => onChange(e.target.value)}
/>
</Wrapper>
);
};

export default SearchBox;
23 changes: 23 additions & 0 deletions src/components/SearchBox/SearchBox.styled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import styled from 'styled-components';
import { HiSearch } from 'react-icons/hi';

export const Wrapper = styled.div`
display: inline-flex;
align-items: center;
position: relative;
margin-bottom: 16px;
text-transform: uppercase;
`;

export const Input = styled.input`
padding: 8px 32px 8px 8px;
border-radius: 4px;
font: inherit;
`;

export const Icon = styled(HiSearch)`
width: 20px;
height: 20px;
position: absolute;
right: 6px;
`;
5 changes: 4 additions & 1 deletion src/components/SharedLayout/SharedLayout.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Container, Header, Logo, Link } from 'components/App/App.styled';
import { Outlet } from 'react-router-dom';
import { Suspense } from 'react';

const Sharedlayout = () => {
return (
Expand All @@ -17,7 +18,9 @@ const Sharedlayout = () => {
<Link to="/products">Products</Link>
</nav>
</Header>
<Outlet />
<Suspense fallback={<h1>Loading page ...</h1>}>
<Outlet />
</Suspense>
</Container>
);
};
Expand Down
20 changes: 10 additions & 10 deletions src/fakeAPI.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
const products = [
{ id: 'h-1', name: 'Hoodie 1' },
{ id: 'h-2', name: 'Hoodie 2' },
{ id: 'h-3', name: 'Hoodie 3' },
{ id: 's-1', name: 'Sneakers 1' },
{ id: 's-2', name: 'Sneakers 2' },
{ id: 's-3', name: 'Sneakers 3' },
{ id: 's-4', name: 'Sneakers 4' },
{ id: 'p-1', name: 'Pants 1' },
{ id: 'p-2', name: 'Pants 2' },
{ id: 'p-3', name: 'Pants 3' },
{ id: 'h-1', name: 'Hoodie 1', color: 'red', maxPrice: 100 },
{ id: 'h-2', name: 'Hoodie 2', color: 'green', maxPrice: 300 },
{ id: 'h-3', name: 'Hoodie 3', color: 'blue', maxPrice: 500 },
{ id: 's-1', name: 'Sneakers 1', color: 'red', maxPrice: 100 },
{ id: 's-2', name: 'Sneakers 2', color: 'green', maxPrice: 300 },
{ id: 's-3', name: 'Sneakers 3', color: 'blue', maxPrice: 500 },
{ id: 's-4', name: 'Sneakers 4', color: 'red', maxPrice: 100 },
{ id: 'p-1', name: 'Pants 1', color: 'red', maxPrice: 100 },
{ id: 'p-2', name: 'Pants 2', color: 'green', maxPrice: 300 },
{ id: 'p-3', name: 'Pants 3', color: 'blue', maxPrice: 500 },
];

export const getProducts = () => {
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import { App } from 'components/App/App';
import App from 'components/App/App';
import './index.css';
import { BrowserRouter } from 'react-router-dom';

Expand Down
6 changes: 4 additions & 2 deletions src/pages/About.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Link, Outlet } from 'react-router-dom';

import { Suspense } from 'react';
const About = () => {
return (
<main>
Expand Down Expand Up @@ -28,7 +28,9 @@ const About = () => {
<Link to="reviews">Go through the reviews</Link>
</li>
</ul>
<Outlet />
<Suspense fallback={<h1>Loading subpage...</h1>}>
<Outlet />
</Suspense>
</main>
);
};
Expand Down
7 changes: 6 additions & 1 deletion src/pages/ProductDetails.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { useParams } from 'react-router-dom';
import { useParams, useLocation } from 'react-router-dom';
import BackLink from 'components/BackLink/BackLink';
import { getProductById } from '../fakeAPI';

const ProductDetails = () => {
const { id } = useParams();
const product = getProductById(id);
const location = useLocation();
const backLinkHref = location.state?.from ?? '/products';

return (
<main>
<BackLink to={backLinkHref}>Back to products</BackLink>
<img src="https://via.placeholder.com/960x240" alt="" />
<div>
<h2>
Expand Down
19 changes: 17 additions & 2 deletions src/pages/Products.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import { ProductList } from '../components/ProductList/ProductList';
import { useSearchParams } from 'react-router-dom';
import SearchBox from 'components/SearchBox/SearchBox';
import ProductList from '../components/ProductList/ProductList';
import { getProducts } from '../fakeAPI';

const Products = () => {
const products = getProducts();
const [searchParams, setSearchParams] = useSearchParams();
const productName = searchParams.get('name') ?? '';

const visibleProducts = products.filter(product =>
product.name.toLowerCase().includes(productName.toLowerCase())
);

const updateQueryString = name => {
const nextParams = name !== '' ? { name } : {};
setSearchParams(nextParams);
};

return (
<main>
<ProductList products={products} />
<SearchBox value={productName} onChange={updateQueryString} />
<ProductList products={visibleProducts} />
</main>
);
};
Expand Down

0 comments on commit 1645cc5

Please sign in to comment.