Compare commits
No commits in common. "5c6e1d778cbc3ad81bc55e48bff0699fc593e797" and "d7ef59f2a6dd6c9d0716cc40a004e04ed4cf55a6" have entirely different histories.
5c6e1d778c
...
d7ef59f2a6
@ -1,37 +1,11 @@
|
|||||||
import { useContext } from "react";
|
|
||||||
import classes from "./Cart.module.css";
|
import classes from "./Cart.module.css";
|
||||||
import Modal from "../UI/Modal";
|
import Modal from "../UI/Modal";
|
||||||
import CartContext from "../../store/cart-context";
|
|
||||||
import CartItem from "./CartItem";
|
|
||||||
|
|
||||||
const Cart = (props) => {
|
const Cart = (props) => {
|
||||||
const cartCtx = useContext(CartContext);
|
|
||||||
|
|
||||||
const totalAmount = `$${cartCtx.totalAmount.toFixed(2)}`;
|
|
||||||
|
|
||||||
const hasItems = cartCtx.items.length > 0;
|
|
||||||
|
|
||||||
const cartItemAddHandler = (item) => {
|
|
||||||
cartCtx.addItem({ ...item, amount: 1 });
|
|
||||||
};
|
|
||||||
|
|
||||||
const cartItemRemoveHandler = (id) => {
|
|
||||||
cartCtx.removeItem(id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const cartItems = (
|
const cartItems = (
|
||||||
<ul className={classes["cart-items"]}>
|
<ul className={classes["cart-items"]}>
|
||||||
{cartCtx.items.map((item) => (
|
{[{ id: "c1", name: "sushi", amount: 2, price: 12.99 }].map((item) => (
|
||||||
<CartItem
|
<li>{item.name}</li>
|
||||||
key={item.id}
|
|
||||||
name={item.name}
|
|
||||||
amount={item.amount}
|
|
||||||
price={item.price}
|
|
||||||
onRemove={cartItemRemoveHandler.bind(null, item.id)}
|
|
||||||
onAdd={cartItemAddHandler.bind(null, item)}
|
|
||||||
>
|
|
||||||
{item.name}
|
|
||||||
</CartItem>
|
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
@ -41,13 +15,13 @@ const Cart = (props) => {
|
|||||||
{cartItems}
|
{cartItems}
|
||||||
<div className={classes.total}>
|
<div className={classes.total}>
|
||||||
<span>Total Amount</span>
|
<span>Total Amount</span>
|
||||||
<span>{totalAmount}</span>
|
<span>35.63</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.actions}>
|
<div className={classes.actions}>
|
||||||
<button className={classes["button--alt"]} onClick={props.onHideCart}>
|
<button className={classes["button--alt"]} onClick={props.onHideCart}>
|
||||||
Close
|
Close
|
||||||
</button>
|
</button>
|
||||||
{hasItems && <button className={classes.button}>Order</button>}
|
<button className={classes.button}>Order</button>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
import classes from './CartItem.module.css';
|
|
||||||
|
|
||||||
const CartItem = (props) => {
|
|
||||||
const price = `$${props.price.toFixed(2)}`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li className={classes['cart-item']}>
|
|
||||||
<div>
|
|
||||||
<h2>{props.name}</h2>
|
|
||||||
<div className={classes.summary}>
|
|
||||||
<span className={classes.price}>{price}</span>
|
|
||||||
<span className={classes.amount}>x {props.amount}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes.actions}>
|
|
||||||
<button onClick={props.onRemove}>−</button>
|
|
||||||
<button onClick={props.onAdd}>+</button>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CartItem;
|
|
@ -1,65 +0,0 @@
|
|||||||
.cart-item {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
border-bottom: 2px solid #8a2b06;
|
|
||||||
padding: 1rem 0;
|
|
||||||
margin: 1rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cart-item h2 {
|
|
||||||
margin: 0 0 0.5rem 0;
|
|
||||||
color: #363636;
|
|
||||||
}
|
|
||||||
|
|
||||||
.summary {
|
|
||||||
width: 10rem;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.price {
|
|
||||||
font-weight: bold;
|
|
||||||
color: #8a2b06;
|
|
||||||
}
|
|
||||||
|
|
||||||
.amount {
|
|
||||||
font-weight: bold;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
padding: 0.25rem 0.75rem;
|
|
||||||
border-radius: 6px;
|
|
||||||
color: #363636;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
.actions {
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.cart-item button {
|
|
||||||
font: inherit;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
color: #8a2b06;
|
|
||||||
border: 1px solid #8a2b06;
|
|
||||||
width: 3rem;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 6px;
|
|
||||||
background-color: transparent;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-left: 1rem;
|
|
||||||
margin: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cart-item button:hover,
|
|
||||||
.cart-item button:active {
|
|
||||||
background-color: #8a2b06;
|
|
||||||
color: white;
|
|
||||||
}
|
|
@ -1,22 +1,9 @@
|
|||||||
import { useContext } from "react";
|
|
||||||
import classes from "./MealItem.module.css";
|
import classes from "./MealItem.module.css";
|
||||||
import MealItemForm from "./MealItemForm";
|
import MealItemForm from "./MealItemForm";
|
||||||
import CartContext from "../../../store/cart-context";
|
|
||||||
|
|
||||||
const MealItem = (props) => {
|
const MealItem = (props) => {
|
||||||
const price = `$${props.price.toFixed(2)}`;
|
const price = `$${props.price.toFixed(2)}`;
|
||||||
|
|
||||||
const cartCtx = useContext(CartContext);
|
|
||||||
|
|
||||||
const addToCartHandler = (amount) => {
|
|
||||||
cartCtx.addItem({
|
|
||||||
id: props.id,
|
|
||||||
name: props.name,
|
|
||||||
amount: amount,
|
|
||||||
price: props.price,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className={classes.meal}>
|
<li className={classes.meal}>
|
||||||
<div>
|
<div>
|
||||||
@ -25,7 +12,7 @@ const MealItem = (props) => {
|
|||||||
<div className={classes.price}>{price}</div>
|
<div className={classes.price}>{price}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<MealItemForm id={props.id} onAddToCart={addToCartHandler} />
|
<MealItemForm id={props.id} />
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
@ -1,33 +1,10 @@
|
|||||||
import classes from "./MealItemForm.module.css";
|
import classes from "./MealItemForm.module.css";
|
||||||
import Input from "../../UI/Input";
|
import Input from "../../UI/Input";
|
||||||
import { useRef, useState } from "react";
|
|
||||||
|
|
||||||
const MealItemForm = (props) => {
|
const MealItemForm = (props) => {
|
||||||
const amountInputRef = useRef();
|
|
||||||
const [amountIsValid, setAmountIsValid] = useState(true);
|
|
||||||
|
|
||||||
const submitHandler = (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
const enteredAmount = amountInputRef.current.value;
|
|
||||||
const enteredAmountNumber = +enteredAmount;
|
|
||||||
|
|
||||||
if (
|
|
||||||
enteredAmount.trim().length === 0 ||
|
|
||||||
enteredAmountNumber < 1 ||
|
|
||||||
enteredAmountNumber > 5
|
|
||||||
) {
|
|
||||||
setAmountIsValid(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
props.onAddToCart(enteredAmountNumber);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className={classes.form} onSubmit={submitHandler}>
|
<form className={classes.form}>
|
||||||
<Input
|
<Input
|
||||||
ref={amountInputRef}
|
|
||||||
label="Amount"
|
label="Amount"
|
||||||
input={{
|
input={{
|
||||||
id: "amount_" + props.id,
|
id: "amount_" + props.id,
|
||||||
@ -39,7 +16,6 @@ const MealItemForm = (props) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<button>+ Add</button>
|
<button>+ Add</button>
|
||||||
{!amountIsValid && <p>Please enter a valid amount (1-5).</p>}
|
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import React from "react";
|
|
||||||
import classes from "./Input.module.css";
|
import classes from "./Input.module.css";
|
||||||
|
|
||||||
const Input = React.forwardRef((props, ref) => {
|
const Input = (props) => {
|
||||||
return (
|
return (
|
||||||
<div className={classes.input}>
|
<div className={classes.input}>
|
||||||
<label htmlFor={props.input.id}>{props.label}</label>
|
<label htmlFor={props.input.id}>{props.label}</label>
|
||||||
<input ref={ref} id={props.input.id} {...props.input} />
|
<input id={props.input.id} {...props.input} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
};
|
||||||
|
|
||||||
export default Input;
|
export default Input;
|
||||||
|
@ -1,86 +1,12 @@
|
|||||||
import { useReducer } from "react";
|
|
||||||
import CartContext from "./cart-context";
|
import CartContext from "./cart-context";
|
||||||
|
|
||||||
const defaultCartState = {
|
|
||||||
items: [],
|
|
||||||
totalAmount: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
const cartReducer = (state, action) => {
|
|
||||||
if (action.type === "ADD_ITEM") {
|
|
||||||
const updatedTotalAmount =
|
|
||||||
state.totalAmount + action.item.price * action.item.amount;
|
|
||||||
|
|
||||||
const existingCartItemIndex = state.items.findIndex(
|
|
||||||
(item) => item.id === action.item.id
|
|
||||||
);
|
|
||||||
|
|
||||||
const existingCartItem = state.items[existingCartItemIndex];
|
|
||||||
let updatedItem;
|
|
||||||
let updatedItems;
|
|
||||||
|
|
||||||
if (existingCartItem) {
|
|
||||||
updatedItem = {
|
|
||||||
...existingCartItem,
|
|
||||||
amount: existingCartItem.amount + action.item.amount,
|
|
||||||
};
|
|
||||||
|
|
||||||
updatedItems = [...state.items];
|
|
||||||
updatedItems[existingCartItemIndex] = updatedItem;
|
|
||||||
} else {
|
|
||||||
updatedItem = { ...action.item };
|
|
||||||
updatedItems = state.items.concat(action.item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return { items: updatedItems, totalAmount: updatedTotalAmount };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.type === "REMOVE_ITEM") {
|
|
||||||
const existingCartItemIndex = state.items.findIndex(
|
|
||||||
(item) => item.id === action.id
|
|
||||||
);
|
|
||||||
|
|
||||||
const existingCartItem = state.items[existingCartItemIndex];
|
|
||||||
|
|
||||||
let updatedTotalAmount = state.totalAmount;
|
|
||||||
if (existingCartItem) {
|
|
||||||
updatedTotalAmount = state.totalAmount - existingCartItem.price;
|
|
||||||
}
|
|
||||||
|
|
||||||
let updatedItems;
|
|
||||||
if (existingCartItem.amount === 1) {
|
|
||||||
// remove the item from array because this is the last item
|
|
||||||
updatedItems = state.items.filter((item) => item.id !== action.id);
|
|
||||||
} else {
|
|
||||||
const updatedItem = {
|
|
||||||
...existingCartItem,
|
|
||||||
amount: existingCartItem.amount - 1,
|
|
||||||
};
|
|
||||||
updatedItems = [...state.items];
|
|
||||||
updatedItems[existingCartItemIndex] = updatedItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { items: updatedItems, totalAmount: updatedTotalAmount };
|
|
||||||
}
|
|
||||||
return defaultCartState;
|
|
||||||
};
|
|
||||||
|
|
||||||
const CartProvider = (props) => {
|
const CartProvider = (props) => {
|
||||||
const [cartState, dispatchCartAction] = useReducer(
|
const addItemToCartHandler = (item) => {};
|
||||||
cartReducer,
|
const removeItemFromCartHandler = (id) => {};
|
||||||
defaultCartState
|
|
||||||
);
|
|
||||||
|
|
||||||
const addItemToCartHandler = (item) => {
|
|
||||||
dispatchCartAction({ type: "ADD_ITEM", item: item });
|
|
||||||
};
|
|
||||||
const removeItemFromCartHandler = (id) => {
|
|
||||||
dispatchCartAction({ type: "REMOVE_ITEM", id: id });
|
|
||||||
};
|
|
||||||
|
|
||||||
const cartContext = {
|
const cartContext = {
|
||||||
items: cartState.items,
|
items: [],
|
||||||
totalAmount: cartState.totalAmount,
|
totalAmount: 0,
|
||||||
addItem: addItemToCartHandler,
|
addItem: addItemToCartHandler,
|
||||||
removeItem: removeItemFromCartHandler,
|
removeItem: removeItemFromCartHandler,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user