REDUX, Codecademy Store: modifying the quantity using the number input field is not working

Hello, I’m completely stuck at end of this project
codecademy store

  • When I select some items at the store and change the quantity by the number input field, the total becomes NaN.
  • When I press the “Add to Cart” button several times, the total price works correctly.

I’ve watched the tutorial video but couldn’t find a solution.
Please give me an advice.

Cart.js

import React from 'react';
import {
  calculateTotal,
  getCurrencySymbol,
} from '../../utilities/utilities.js';
import {changeItemQuantity} from './cartSlice.js'

export const Cart = (props) => {
  const { cart, currencyFilter, dispatch } = props;

  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 an action to change the quantity of the given name and quantity.
  dispatch(changeItemQuantity(name, newQuantity));
  };

  // Use the cart and currencyFilter slices to render their data.
  const cartElements = Object.keys(cart).map(createCartItem);

  const total = calculateTotal(cart, currencyFilter);

  return (
    <div id="cart-container">
      <ul id="cart-items">{cartElements}</ul>
      <h3 className="total">
        Total{' '}
        <span className="total-value">
          {getCurrencySymbol(currencyFilter)}{total} {currencyFilter}
        </span>
      </h3>
    </div>
  );

  function createCartItem(name) {
    const item = cart[name];

    if (item.quantity === 0) {
      return;
    }

    return (
      <li key={name}>
        <p>{name}</p>
        <select
          className="item-quantity"
          value={item.quantity}
          onChange={(e) => {
            onInputChangeHandler(name, e.target.value);
          }}
        >
          {[...Array(100).keys()].map((_, index) => (
            <option key={index} value={index}>
              {index}
            </option>
          ))}
        </select>
      </li>
    );
  }
};

cartSlice.js

export const addItem = (itemToAdd) => {
  return {
    type: 'cart/addItem',
    payload: itemToAdd,
  };
};

export const changeItemQuantity = (name, newQuantity) => {
  return {
    type: 'cart/changeItemQuantity',
    payload: {
      name: name,
      quantity: newQuantity
    },
  }
}

const initialCart = {};
export const cartReducer = (cart = initialCart, action) => {
  switch (action.type) {
    case 'cart/addItem': {
      const { name, price } = 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, quantity };

      // Add the new item to the cart (or replace it if it existed already)
      return { 
        ...cart, 
        [name]: newItem 
      };
    }
    case 'cart/changeItemQuantity': {
      const { name, newQuantity } = action.payload;
      const itemToUpdate = cart[name];
      
      // Create a copy of itemToUpdate and update the quantity prop.
      const updatedItem = {
        ...itemToUpdate,
        quantity: newQuantity
      };
    
      // Return a copy of the cart with the updatedItem included.
      return {
        ...cart,
        [name]: updatedItem
      }
    }
    default: {
      return cart;
    }
  }
};

App.js

import React from 'react';

import { Inventory } from '../features/inventory/Inventory.js';
import { CurrencyFilter } from '../features/currencyFilter/CurrencyFilter.js';
import { Cart } from '../features/cart/Cart.js';

// Render the Cart component below <Inventory />
export const App = (props) => {

  const { state, dispatch } = props;

  return (
    <div>
      <CurrencyFilter
        currencyFilter={state.currencyFilter}
        dispatch={dispatch}
      />

      <Inventory
        inventory={state.inventory}
        currencyFilter={state.currencyFilter}
        dispatch={dispatch}
      />

      <Cart
        cart={state.cart}
        currencyFilter={state.currencyFilter}
        dispatch={dispatch}
      />

    </div>
  );
};

Hey,
what exactly will be passed to onInputChangeHandler as input? A number with a Dollar or Euro sign etc.? Then Number() isn’t the method of choice as it will throw NaN in that case.

With this:

you just filter out an empty string.
Something like 10€ will be passed to the Number() method and throe NaN.

From this article:
parseFloat():

var text = '3.14someRandomStuff';
var pointNum = parseFloat(text);
// returns 3.14

Number():

// Convert strings
Number('123'); // returns 123
Number('12.3'); // returns 12.3
Number('3.14someRandomStuff'); // returns NaN
Number('42px'); // returns NaN
1 Like

Thanks for commenting @mirja_t,
By your comment, I could check carefully what data the “newQuantity” is holding.

And I realize that the below coding was a bit wrong. And then, now all work correctly!
Thank you.

wrong: quantity: newQuantity
correct: newQuantity: newQuantity

1 Like