+

+
+
{props.title}
+
+ {props.size} | {props.style}
-
X | Front tie dye
-
print Quantity: 1
+
Quantity: {props.quantity}
-
-
x
-
$ 19.00
+
+
handleRemoveItem(props.id)}>
+ x
+
+
$ {(props.quantity * props.price).toFixed(2)}
-
-
+ handleIncrement(props.id)} />
+ {} : () => handleDecrement(props.id)
+ }
+ />
);
}
-function Increment() {
+function Increment(props) {
return (
);
}
-function Decrement() {
+function Decrement(props) {
return (
);
diff --git a/src/components/Products.js b/src/components/Products.js
index 70f47d8..3b630d3 100644
--- a/src/components/Products.js
+++ b/src/components/Products.js
@@ -1,5 +1,8 @@
import React from "react";
import OrderBy from "./OrderBy";
+import { connect } from "react-redux";
+import { useDispatch } from "react-redux";
+import { addProductToCart } from "../store/actions";
class Products extends React.Component {
constructor(props) {
@@ -25,16 +28,20 @@ class Products extends React.Component {
render() {
let { selectedOrder } = this.state;
- let products = this.handleOrderProducts(selectedOrder, this.props.data);
+
+ const data =
+ this.props.sizes.length !== 0
+ ? this.props.data.filter((item) =>
+ item.availableSizes.some((size) => this.props.sizes.includes(size))
+ )
+ : this.props.data;
+
+ let products = this.handleOrderProducts(selectedOrder, data);
return (
-
- {`${this.props.data.length} Product${
- this.props.data.length > 1 ? "s" : ""
- } found.`}{" "}
-
+
{`${data.length} Product${data.length > 1 ? "s" : ""} found.`}
{products.map((product) => (
-
+
))}
@@ -51,6 +58,12 @@ class Products extends React.Component {
}
function Product(props) {
+ const dispatch = useDispatch();
+
+ const handleClick = (product) => {
+ dispatch(addProductToCart(product));
+ };
+
return (
Free Shipping
@@ -65,9 +78,25 @@ function Product(props) {
{props.currencyFormat + props.price}
-
+
);
}
-export default Products;
+export default connect(mapStateToProps)(Products);
+
+function mapStateToProps(state) {
+ return {
+ sizes: state.sizes,
+ };
+}
diff --git a/src/components/Sidebar.js b/src/components/Sidebar.js
index a05b530..73e9c73 100644
--- a/src/components/Sidebar.js
+++ b/src/components/Sidebar.js
@@ -1,14 +1,30 @@
+import { useDispatch, useSelector } from "react-redux";
+import selectSize from "../store/actions";
function Sidebar({ products }) {
let sizes = products.reduce((acc, cv) => {
acc = acc.concat(cv.availableSizes);
return acc;
}, []);
let uniqueSizes = [...new Set(sizes)];
+
+ const dispatch = useDispatch();
+ const sizesState = useSelector((state) => state.sizes);
+
+ const handleClick = (size) => {
+ dispatch(selectSize(size));
+ };
+
return (
diff --git a/src/index.js b/src/index.js
index 47e9199..0fa581e 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,6 +1,13 @@
import React from "react";
import { render } from "react-dom";
+import { Provider } from "react-redux";
import App from "./components/App";
import "./style/index.css";
+import store from "../src/store";
-render(
, document.getElementById("root"));
+render(
+
+
+ ,
+ document.getElementById("root")
+);
diff --git a/src/store/actions.js b/src/store/actions.js
new file mode 100644
index 0000000..6fc1ee5
--- /dev/null
+++ b/src/store/actions.js
@@ -0,0 +1,34 @@
+export default function selectSize(size) {
+ return {
+ type: "select_size",
+ payload: size,
+ };
+}
+
+export function addProductToCart(product) {
+ return {
+ type: "add_product",
+ payload: product,
+ };
+}
+
+export function incrementQuantity(id) {
+ return {
+ type: "increment_quantity",
+ payload: id,
+ };
+}
+
+export function decrementQuantity(id) {
+ return {
+ type: "decrement_quantity",
+ payload: id,
+ };
+}
+
+export function removeItem(id) {
+ return {
+ type: "remove_item",
+ payload: id,
+ };
+}
diff --git a/src/store/index.js b/src/store/index.js
new file mode 100644
index 0000000..f5c873f
--- /dev/null
+++ b/src/store/index.js
@@ -0,0 +1,59 @@
+import { createStore } from "redux";
+
+const initialState = {
+ sizes: [],
+ cart: [],
+};
+
+function incQuantity(state, id) {
+ return {
+ ...state,
+ cart: state.cart.map((product) => {
+ if (product.id === id) {
+ product.quantity++;
+ }
+ return product;
+ }),
+ };
+}
+
+function reducer(state = initialState, action) {
+ switch (action.type) {
+ case "select_size":
+ return state.sizes.includes(action.payload)
+ ? {
+ ...state,
+ sizes: state.sizes.filter((size) => size !== action.payload),
+ }
+ : { ...state, sizes: [...state.sizes, action.payload] };
+ case "add_product":
+ if (state.cart.some((product) => product.id === action.payload.id)) {
+ return incQuantity(state, action.payload.id);
+ }
+ return { ...state, cart: [...state.cart, action.payload] };
+
+ case "remove_item":
+ return {
+ ...state,
+ cart: state.cart.filter((product) => product.id !== action.payload),
+ };
+ case "increment_quantity":
+ return incQuantity(state, action.payload);
+
+ case "decrement_quantity":
+ return {
+ ...state,
+ cart: state.cart.map((product) => {
+ if (product.id === action.payload) {
+ product.quantity--;
+ }
+ return product;
+ }),
+ };
+ default:
+ return state;
+ }
+}
+
+let store = createStore(reducer);
+export default store;
diff --git a/yarn.lock b/yarn.lock
index 91f0999..be14c4a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1179,6 +1179,13 @@
dependencies:
regenerator-runtime "^0.13.4"
+"@babel/runtime@^7.12.1", "@babel/runtime@^7.9.2":
+ version "7.20.1"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.1.tgz#1148bb33ab252b165a06698fde7576092a78b4a9"
+ integrity sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==
+ dependencies:
+ regenerator-runtime "^0.13.10"
+
"@babel/runtime@^7.5.1", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2":
version "7.7.6"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.6.tgz#d18c511121aff1b4f2cd1d452f1bac9601dd830f"
@@ -1843,6 +1850,14 @@
dependencies:
"@types/node" "*"
+"@types/hoist-non-react-statics@^3.3.1":
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
+ integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
+ dependencies:
+ "@types/react" "*"
+ hoist-non-react-statics "^3.3.0"
+
"@types/html-minifier-terser@^5.0.0":
version "5.1.1"
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#3c9ee980f1a10d6021ae6632ca3e79ca2ec4fb50"
@@ -1989,6 +2004,11 @@
dependencies:
source-map "^0.6.1"
+"@types/use-sync-external-store@^0.0.3":
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
+ integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
+
"@types/webpack-sources@*":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-2.1.0.tgz#8882b0bd62d1e0ce62f183d0d01b72e6e82e8c10"
@@ -5735,6 +5755,13 @@ hmac-drbg@^1.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
+hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
+ integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
+ dependencies:
+ react-is "^16.7.0"
+
hoopy@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d"
@@ -9551,6 +9578,11 @@ react-error-overlay@^6.0.9:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
+react-is@^16.7.0:
+ version "16.13.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+ integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+
react-is@^16.8.1, react-is@^16.8.4:
version "16.12.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c"
@@ -9561,6 +9593,23 @@ react-is@^17.0.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339"
integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==
+react-is@^18.0.0:
+ version "18.2.0"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
+ integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
+
+react-redux@^8.0.5:
+ version "8.0.5"
+ resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.5.tgz#e5fb8331993a019b8aaf2e167a93d10af469c7bd"
+ integrity sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==
+ dependencies:
+ "@babel/runtime" "^7.12.1"
+ "@types/hoist-non-react-statics" "^3.3.1"
+ "@types/use-sync-external-store" "^0.0.3"
+ hoist-non-react-statics "^3.3.2"
+ react-is "^18.0.0"
+ use-sync-external-store "^1.0.0"
+
react-refresh@^0.8.3:
version "0.8.3"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f"
@@ -9729,6 +9778,13 @@ redent@^3.0.0:
indent-string "^4.0.0"
strip-indent "^3.0.0"
+redux@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.0.tgz#46f10d6e29b6666df758780437651eeb2b969f13"
+ integrity sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==
+ dependencies:
+ "@babel/runtime" "^7.9.2"
+
regenerate-unicode-properties@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
@@ -9746,6 +9802,11 @@ regenerator-runtime@^0.11.0:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
+regenerator-runtime@^0.13.10:
+ version "0.13.11"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
+ integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
+
regenerator-runtime@^0.13.2:
version "0.13.3"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5"
@@ -11452,6 +11513,11 @@ url@^0.11.0:
punycode "1.3.2"
querystring "0.2.0"
+use-sync-external-store@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
+ integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
+
use@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"