Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
package-lock.json
src
1,048 changes: 487 additions & 561 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jest": "^24.3.5",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-markdown": "^2.0.1",
"eslint-plugin-markdown": "^2.2.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.23.2",
Expand Down
134 changes: 91 additions & 43 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react";
import React, { useEffect, useReducer } from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";

import Home from "./pages/Home";
Expand All @@ -9,6 +9,9 @@ import * as api from "./api";
import useLocalStorage from "./hooks/useLocalStorage";
import loadLocalStorageItems from "./utils/loadLocalStorageItems";

import HomeContext from "./context/HomeContext";
import NewProductContext from "./context/NewProductContext";

function buildNewCartItem(cartItem) {
if (cartItem.quantity >= cartItem.unitsInStock) {
return cartItem;
Expand All @@ -29,35 +32,66 @@ function buildNewCartItem(cartItem) {
const PRODUCTS_LOCAL_STORAGE_KEY = "react-sc-state-products";
const CART_ITEMS_LOCAL_STORAGE_KEY = "react-sc-state-cart-items";

const actionTypes = {
FETCH_INIT: "FETCH_INIT",
FETCH_DONE: "FETCH_DONE",
FETCH_ERROR: "FETCH_ERROR",
CHANGE_PRODUCTS: "CHANGE_PRODUCTS",
CHANGE_CART: "CHANGE_CART",
SAVE_PRODUCT: "SAVE_PRODUCT",
};

const initialState = {
products: loadLocalStorageItems(PRODUCTS_LOCAL_STORAGE_KEY, []),
cartItems: loadLocalStorageItems(CART_ITEMS_LOCAL_STORAGE_KEY, []),
isLoading: false,
hasError: false,
loadingError: null,
};

function reducer(state, action) {
switch (action.type) {
case actionTypes.FETCH_INIT:
return { ...state, isLoading: true };
case actionTypes.FETCH_DONE:
return { ...state, products: [...action.payload], isLoading: false };
case actionTypes.FETCH_ERROR:
return {
...state,
isLoading: false,
hasError: true,
loadingError: action.payload,
};
case actionTypes.CHANGE_PRODUCTS:
return { ...state, products: [...action.payload] };
case actionTypes.CHANGE_CART:
return { ...state, cartItems: [...action.payload] };
case actionTypes.SAVE_PRODUCT:
return { ...state, products: [...products, action.payload] };

default:
return state;
}
}

function App() {
const [products, setProducts] = useState(() =>
loadLocalStorageItems(PRODUCTS_LOCAL_STORAGE_KEY, []),
);
const [cartItems, setCartItems] = useState(() =>
loadLocalStorageItems(CART_ITEMS_LOCAL_STORAGE_KEY, []),
);
const [state, dispatch] = useReducer(reducer, initialState);

const { products, cartItems, isLoading, hasError, loadingError } = state;
useLocalStorage(products, PRODUCTS_LOCAL_STORAGE_KEY);
useLocalStorage(cartItems, CART_ITEMS_LOCAL_STORAGE_KEY);

const [isLoading, setIsLoading] = useState(false);
const [hasError, setHasError] = useState(false);
const [loadingError, setLoadingError] = useState(null);

useEffect(() => {
if (products.length === 0) {
setIsLoading(true);
dispatch({ type: actionTypes.FETCH_INIT });

api
.getProducts()
.then((data) => {
setProducts(data);
setIsLoading(false);
dispatch({ type: actionTypes.FETCH_DONE, payload: data });
})
.catch((error) => {
setIsLoading(false);
setHasError(true);
setLoadingError(error.message);
dispatch({ type: actionTypes.FETCH_ERROR, payload: error });
});
}
}, []);
Expand All @@ -82,12 +116,17 @@ function App() {
};
});

setCartItems(updatedCartItems);
dispatch({ type: actionTypes.CHANGE_CART, payload: updatedCartItems });

return;
}

const updatedProduct = buildNewCartItem(foundProduct);
setCartItems((prevState) => [...prevState, updatedProduct]);

dispatch({
type: actionTypes.CHANGE_CART,
payload: [...cartItems, updatedProduct],
});
}

function handleChange(event, productId) {
Expand All @@ -102,15 +141,13 @@ function App() {
return item;
});

setCartItems(updatedCartItems);
dispatch({ type: actionTypes.CHANGE_CART, payload: updatedCartItems });
}

function handleRemove(productId) {
const updatedCartItems = cartItems.filter((item) => item.id !== productId);

setCartItems(updatedCartItems);
dispatch({ type: actionTypes.CHANGE_CART, payload: updatedCartItems });
}

function handleDownVote(productId) {
const updatedProducts = products.map((product) => {
if (
Expand All @@ -132,8 +169,7 @@ function App() {

return product;
});

setProducts(updatedProducts);
dispatch({ type: actionTypes.CHANGE_PRODUCTS, payload: updatedProducts });
}

function handleUpVote(productId) {
Expand All @@ -157,7 +193,7 @@ function App() {
return product;
});

setProducts(updatedProducts);
dispatch({ type: actionTypes.CHANGE_PRODUCTS, payload: updatedProducts });
}

function handleSetFavorite(productId) {
Expand All @@ -172,34 +208,46 @@ function App() {
return product;
});

setProducts(updatedProducts);
dispatch({ type: actionTypes.CHANGE_PRODUCTS, payload: updatedProducts });
}

function saveNewProduct(newProduct) {
setProducts((prevState) => [newProduct, ...prevState]);
dispatch({
type: actionTypes.CHANGE_PRODUCTS,
payload: [newProduct, ...products],
});
}

return (
<BrowserRouter>
<Switch>
<Route path="/new-product">
<NewProduct saveNewProduct={saveNewProduct} />
<NewProductContext.Provider
value={{
saveNewProduct: saveNewProduct,
}}
>
<NewProduct />
</NewProductContext.Provider>
</Route>
<Route path="/" exact>
<Home
fullWidth
cartItems={cartItems}
products={products}
isLoading={isLoading}
hasError={hasError}
loadingError={loadingError}
handleDownVote={handleDownVote}
handleUpVote={handleUpVote}
handleSetFavorite={handleSetFavorite}
handleAddToCart={handleAddToCart}
handleRemove={handleRemove}
handleChange={handleChange}
/>
<HomeContext.Provider
value={{
cartItems: cartItems,
products: products,
isLoading: isLoading,
hasError: hasError,
loadingError: loadingError,
handleDownVote: handleDownVote,
handleUpVote: handleUpVote,
handleSetFavorite: handleSetFavorite,
handleAddToCart: handleAddToCart,
handleRemove: handleRemove,
handleChange: handleChange,
}}
>
<Home fullWidth />
</HomeContext.Provider>
</Route>
</Switch>
</BrowserRouter>
Expand Down
10 changes: 5 additions & 5 deletions src/components/Cart/Cart.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import React from "react";
import React, { useContext } from "react";

import ShoppingCartItem from "../ShoppingCartItem";
import Button from "../Button";
import HomeContext from "../../context/HomeContext";

function getCartTotal(cart) {
return cart.reduce((accum, item) => {
return accum + item.price * item.quantity;
}, 0);
}

function Cart({ cartItems, handleRemove, handleChange, ...props }) {
function Cart() {
const { cartItems } = useContext(HomeContext);
return (
<aside {...props}>
<aside className="col col-4">
<div className="row flex-column">
<div className="col shopping__cart__header">
<h2 className="h3 mt-2">Shopping Cart</h2>
Expand All @@ -28,8 +30,6 @@ function Cart({ cartItems, handleRemove, handleChange, ...props }) {
img={item.img}
quantity={item.quantity}
unitsInStock={item.unitsInStock}
handleRemove={handleRemove}
handleChange={handleChange}
/>
))
) : (
Expand Down
13 changes: 8 additions & 5 deletions src/components/ItemCard/ItemCard.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from "react";
import React, { useContext } from "react";

import FavoriteIconButton from "../FavoriteIconButton";
import IconButton from "../IconButton";
import Button from "../Button";
import { ThumbDown, ThumbUp } from "../SVGIcons";

import "./ItemCard.scss";
import HomeContext from "../../context/HomeContext";

function Divider() {
return <hr className="ItemCard__divider" />;
Expand Down Expand Up @@ -34,11 +35,13 @@ function ItemCard({
isFavorite,
upVotes,
downVotes,
handleDownVote,
handleUpVote,
handleSetFavorite,
handleAddToCart,
}) {
const {
handleDownVote,
handleUpVote,
handleSetFavorite,
handleAddToCart,
} = useContext(HomeContext);
function onDownVote() {
handleDownVote(id);
}
Expand Down
7 changes: 6 additions & 1 deletion src/components/NewProductForm/NewProductForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import Input from "../Input";
import Button from "../Button";

import productSchema from "./product-schema";
import NewProductContext from "../../context/NewProductContext";
import { useContext } from "react";

function addProductDetails(product) {
return {
Expand All @@ -33,7 +35,8 @@ function addProductDetails(product) {
};
}

function NewProductForm({ saveNewProduct }) {
function NewProductForm() {
const { saveNewProduct } = useContext(NewProductContext);
const [hasSubmitted, setHasSubmitted] = useState(false);

const formik = useFormik({
Expand All @@ -51,6 +54,8 @@ function NewProductForm({ saveNewProduct }) {
validationSchema: productSchema,
onSubmit: (values, { setSubmitting }) => {
const newProduct = addProductDetails(values);
console.log(saveNewProduct);

saveNewProduct(newProduct);
setSubmitting(true);

Expand Down
19 changes: 5 additions & 14 deletions src/components/ProductsListing/ProductsListing.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import React from "react";
import React, { useContext } from "react";
import HomeContext from "../../context/HomeContext";

import ItemCard from "../ItemCard";

function ProductsListing({
products,
handleDownVote,
handleUpVote,
handleSetFavorite,
handleAddToCart,
...props
}) {
function ProductsListing() {
const { products } = useContext(HomeContext);
return (
<section className="row" {...props}>
<section className="row">
{products.map((product) => (
<ItemCard
key={product.id}
Expand All @@ -20,12 +15,8 @@ function ProductsListing({
title={product.title}
shortDescription={product.shortDescription}
upVotes={product.votes.upVotes}
handleUpVote={handleUpVote}
downVotes={product.votes.downVotes}
handleDownVote={handleDownVote}
isFavorite={product.isFavorite}
handleSetFavorite={handleSetFavorite}
handleAddToCart={handleAddToCart}
/>
))}
</section>
Expand Down
15 changes: 4 additions & 11 deletions src/components/ShoppingCartItem/ShoppingCartItem.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from "react";
import React, { useContext } from "react";

import "./ShoppingCartItem.scss";

import Button from "../Button";
import HomeContext from "../../context/HomeContext";

function buildSelectOptions(unitsInStock) {
return Array.from({ length: unitsInStock }, (_value, index) => {
Expand All @@ -15,16 +16,8 @@ function buildSelectOptions(unitsInStock) {
});
}

function ShoppingCartItem({
id,
img,
title,
price,
quantity,
unitsInStock,
handleChange,
handleRemove,
}) {
function ShoppingCartItem({ id, img, title, price, quantity, unitsInStock }) {
const { handleRemove, handleChange } = useContext(HomeContext);
function onHandleChange(event) {
handleChange(event, id);
}
Expand Down
Loading