I know similar questions have been asked, but I couldn't find one which I could adapt to my code (possibly cause I am still new to Redux). So, I am editing the cart functionality which was already written and where I already have two functions:
- Update the quantity number whenever user adds or removes product(s).
- Update the total price of added products. At the moment, quantity number is displayed via input with its default arrows (therefore it's not very touchscreen-friendly), and the user can't really delete the starting number 1 in order to 'manually' change the quantity by typing in. My job is to make increment and decrement buttons along with different input where user will also be able to type in the desired quantity. How can I do this?
export function calculateTotal(cart) {
let totalUSD = 0;
Object.keys(cart).forEach((itemName) => {
totalUSD += cart[itemName].price * cart[itemName].quantity;
});
return totalUSD.toFixed(2);
}
export function calculateTotal(cart) {
let totalUSD = 0;
Object.keys(cart).forEach((itemName) => {
totalUSD += cart[itemName].price * cart[itemName].quantity;
});
return totalUSD.toFixed(2);
}
export function calculateTotalQuantity(cart) {
let totalQuantity = 0;
Object.keys(cart).forEach((itemName) => {
totalQuantity += cart[itemName].quantity;
});
return totalQuantity;
}
import React from 'react';
import "./Cart.css";
import Navbar from './Navbar.jsx';
import Footer from './Footer.jsx';
import { useDispatch, useSelector } from 'react-redux';
import { changeItemQuantity } from '../features/cart/cartSlice.js';
import { calculateTotal } from '../features/utilities/utilities.js';
import { removeAll } from '../features/cart/cartSlice.js';
export default function Cart() {
const dispatch = useDispatch();
const cart = useSelector(state => state.cart); // * Note
const onInputChangeHandler = (name, input) => {
// If the user enters a bad value...
if (input === '') {
return;
}
// Otherwise, convert the input into a number and pass it along as the newQuantity.
const newQuantity = Number(input);
dispatch(changeItemQuantity(name, newQuantity));
};
const onRemoveAll = () => {
dispatch(removeAll());
};
// Use the cart and currencyFilter slices to render their data.
const cartElements = Object.entries(cart).map(createCartItem);
const total = calculateTotal(cart);
return (
<>
<Navbar/>
<div id="cart-container">
<ul id="cart-items">
{cartElements == '' ? <div className="cart-empty">Your cart is empty</div> : cartElements}
</ul>
<div className="price-btn-container">
{cartElements.length > 0 ? <button
onClick={() => onRemoveAll()}
className="remove-all"
>
Remove All
</button> : <div></div>}
<h3 className="total">
Total{' '}
<span className="total-value">
${total}
</span>
</h3>
</div>
</div>
<Footer/>
</>
);
function createCartItem([name, item]) {
if (item.quantity === 0) {
return;
}
return (
<li className="cart-list" key={name}>
<img src={item.img}/>
<p>{name}</p>
<p>{item.type}</p>
<div className="quantity-container">
<p>Quantity:</p>
<input
type="number"
className="item-quantity"
name="quantity"
value={item.quantity}
onChange={(e) => {
onInputChangeHandler(name, e.target.value);
}}/>
</div>
</li>
);
}
};
export const addItem = (itemToAdd) => {
return {
type: 'cart/addItem',
payload: itemToAdd,
};
};
export const removeAll = () => {
return {
type: 'cart/removeAll',
payload: initialCart
}
}
export const changeItemQuantity = (name, newQuantity ) => {
return {
type: 'cart/changeItemQuantity',
payload: {
name,
newQuantity
}
}
}
const initialCart = [];
export const cartReducer = (cart = initialCart, action) => {
switch (action.type) {
case 'cart/addItem': {
const { name, price, img, type } = action.payload;
// if the item already exists, increase the quantity by 1, otherwise set it to 1
const quantity = cart[name] ? cart[name].quantity + 1 : 1;
const newItem = { price, img, type, quantity };
// Add the new item to the cart (or replace it if it existed already)
return {
...cart,
[name]: newItem
};
}
case 'cart/removeItem':
return cart.filter(item => item !== action.payload);
case 'cart/removeAll':
return initialCart;
case 'cart/changeItemQuantity': {
const { name, newQuantity } = action.payload;
const itemToUpdate = cart[name];
const updatedItem = {
...itemToUpdate,
quantity: newQuantity
}
// Create a copy of itemToUpdate and update the quantity prop.
return {
...cart,
[name]: updatedItem
}
}
default: {
return cart;
}
}
};
Create two new actions/reducer cases to increment/decrement the item quantity.
If you don't want the extra actions/reducers, you could handle it with the
changeItemQuantityaction.