Skip to content

Commit

Permalink
shop
Browse files Browse the repository at this point in the history
  • Loading branch information
NguyenHHKiet committed Jun 26, 2023
1 parent ca82cf4 commit 5030ba1
Show file tree
Hide file tree
Showing 18 changed files with 468 additions and 55 deletions.
24 changes: 20 additions & 4 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 @@ -8,6 +8,7 @@
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"bootstrap": "^5.3.0",
"bootstrap-icons": "^1.10.5",
"react": "^18.2.0",
"react-bootstrap": "^2.8.0",
"react-dom": "^18.2.0",
Expand Down
4 changes: 2 additions & 2 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createBrowserRouter, RouterProvider } from "react-router-dom";
import Root from "./components/Layout/Root";
import Error from "./pages/Error";
import HomePage, { loader as homeLoader } from "./pages/HomePage";
import ShopPage from "./pages/ShopPage";
import ShopPage, { loader as shopLoader } from "./pages/ShopPage";
import DetailPage from "./pages/DetailPage";
import CartPage from "./pages/CartPage";
import CheckoutPage from "./pages/CheckoutPage";
Expand All @@ -17,7 +17,7 @@ const router = createBrowserRouter([
errorElement: <Error />,
children: [
{ index: true, element: <HomePage />, loader: homeLoader },
{ path: "shop", element: <ShopPage /> },
{ path: "shop", element: <ShopPage />, loader: shopLoader },
{ path: "detail/:productId", element: <DetailPage /> },
{ path: "cart", element: <CartPage /> },
{ path: "checkout", element: <CheckoutPage /> },
Expand Down
50 changes: 35 additions & 15 deletions src/components/ListOfProducts/ListOfProducts.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,46 @@
import React, { useState } from "react";
import React, { Fragment, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import Row from "react-bootstrap/Row";

import classes from "./ListOfProducts.module.scss";
import ProductItem from "./ProductItem";
import ProductDetail from "../Products/ProductDetail";

const ListOfProducts = ({ data }) => {
const dispatch = useDispatch();
const isClose = useSelector((state) => state.onClose);
const [detail, setDetail] = useState(null);

if (detail) {
dispatch({ type: "SHOW_POPUP", payload: detail.info });
setDetail(null);
}

return (
<div className="py-3">
<div className={classes.title}>
<h6 className="fst-italic text-uppercase">Made the hard way</h6>
<h1 className="fst-italic text-uppercase">
Top trending products
</h1>
</div>
<div className={`${classes.images} d-grid gap-4 py-4`}>
<Row>
{data.map((product) => (
<ProductItem product={product} />
))}
</Row>
<Fragment>
{isClose && <ProductDetail />}
<div className="py-3">
<div className={classes.title}>
<h6 className="fst-italic text-uppercase">
Made the hard way
</h6>
<h1 className="fst-italic text-uppercase">
Top trending products
</h1>
</div>
<div className={`d-grid gap-4 py-4`}>
<Row>
{data.map((product) => (
<ProductItem
key={product._id["$oid"]}
product={product}
setDetail={setDetail}
/>
))}
</Row>
</div>
</div>
</div>
</Fragment>
);
};

Expand Down
4 changes: 4 additions & 0 deletions src/components/ListOfProducts/ListOfProducts.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
color: gray;
font-size: 0.9rem;
}
a {
color: black;
text-decoration: none;
}
}

.product-content * {
Expand Down
59 changes: 40 additions & 19 deletions src/components/ListOfProducts/ProductItem.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,48 @@
import React from "react";
import Col from "react-bootstrap/Col";
import classes from "./ListOfProducts.module.scss";
import { NavLink } from "react-router-dom";

const ProductItem = ({ product, setDetail, isLink }) => {
const price = `${Number(product.price)
.toLocaleString("vi-VN", { style: "currency", currency: "VND" })
.slice(0, -1)} VND`;
function onClickHandler() {
const transformData = {
info: {
name: product.name,
price: price,
category: product.category,
img: product.img1,
long_desc: product.long_desc,
short_desc: product.short_desc,
_id: {
$oid: product._id.$oid,
},
},
onClose: true,
};
setDetail(transformData);
}

const ProductItem = ({ product }) => {
return (
<Col key={product._id.$oid} xs={6} md={3}>
<article>
<figure>
<img src={product.img1} alt="img1" />
</figure>
<div className={classes["product-content"]}>
<h6>{product.name}</h6>
<p>
{Number(product.price)
.toLocaleString("vi-VN", {
style: "currency",
currency: "VND",
})
.slice(0, -1)}
VND
</p>
</div>
</article>
<Col
key={product._id.$oid}
xs={6}
md={3}
onClick={onClickHandler}
className={classes.images}>
<NavLink to={isLink ? `/detail/${product._id.$oid}` : "/"}>
<article>
<figure>
<img src={product.img1} alt="img1" loading="lazy" />
</figure>
<div className={classes["product-content"]}>
<h6>{product.name}</h6>
<p>{price}</p>
</div>
</article>
</NavLink>
</Col>
);
};
Expand Down
120 changes: 120 additions & 0 deletions src/components/Products/Categories/Categories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import React, { useState } from "react";
import { Link, useLoaderData, useSearchParams } from "react-router-dom";
import Form from "react-bootstrap/Form";
import InputGroup from "react-bootstrap/InputGroup";

import classes from "./Categories.module.scss";
import ProductItem from "../../ListOfProducts/ProductItem";
import Row from "react-bootstrap/esm/Row";
import { useDispatch } from "react-redux";

const arrTitle = [
"APPLE",
"All",
"IPHONE & MAC",
"iPhone",
"iPad",
"Macbook",
"WIRELESS",
"Airpod",
"Watch",
"OTHER",
"Mouse",
"Keyboard",
"Other",
];

const Categories = () => {
const data = useLoaderData();
const [params] = useSearchParams();
const sortId = params.get("sort");

const dispatch = useDispatch();
const [detail, setDetail] = useState(null);

if (detail) {
dispatch({ type: "SELECT", payload: detail.info });
setDetail(null);
}

let content = data;
if (sortId) {
switch (sortId.toLowerCase()) {
case "all":
content = data;
break;

default:
content = data.filter(
(item) => item.category === sortId.toLowerCase()
);
break;
}
}

const Title = (item) => {
let linked;
if (
item !== "APPLE" &&
item !== "IPHONE & MAC" &&
item !== "WIRELESS" &&
item !== "OTHER"
) {
linked = `?sort=${item}`;
}
return (
<Link
key={item}
className="px-3 py-2 fst-italic fw-light"
to={linked}>
{item}
</Link>
);
};

return (
<div className={`${classes.showcase} gap-4`}>
<div className="">
<h3 className="text-uppercase fst-italic mb-3">Categories</h3>
<div className={classes.arrTitle}>
{arrTitle.map((item) => Title(item))}
</div>
</div>
<div>
<div className="d-flex justify-content-between mb-3">
<InputGroup className={`${classes.input}`}>
<Form.Control
placeholder="Enter Search Here!"
aria-label="Enter Search Here!"
className="py-2"
/>
</InputGroup>
<Form.Select className={classes.select}>
<option>Default sorting</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</Form.Select>
</div>
<div className={`d-grid gap-4 py-4`}>
<Row>
{content.length > 0 ? (
content.map((product) => (
<ProductItem
key={product._id.$oid}
product={product}
setDetail={setDetail}
isLink={true}
/>
))
) : (
<p>Not Found Product</p>
)}
</Row>
</div>
</div>
</div>
);
};

export default Categories;
48 changes: 48 additions & 0 deletions src/components/Products/Categories/Categories.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.showcase {
display: grid;
grid-template-columns: 2.5fr 7.5fr;
height: 100vh;
.arrTitle {
display: flex;
flex-direction: column;
font-size: smaller;
> * {
text-decoration: none;
color: black;
}
> *:hover {
background-color: #f8f8f8;
}
:nth-child(1) {
background-color: black;
color: white;
font-size: medium;
}
:nth-child(3) {
background-color: #e2e4e2;
color: black;
font-size: medium;
font-weight: 400 !important;
}
:nth-child(7) {
background-color: #e2e4e2;
color: black;
font-size: medium;
font-weight: 400 !important;
}
:nth-child(10) {
background-color: #e2e4e2;
color: black;
font-size: medium;
font-weight: 400 !important;
}
}
}

.input {
max-width: 20rem;
}

.select {
max-width: 10rem;
}
Loading

0 comments on commit 5030ba1

Please sign in to comment.