skip to Main Content

When the HandlePayNow function is called, it executes all of its intended functionality but then crashes the system. It sends the order data to the API, the API logs it and returns a success message, the function gets this success message, it displays it’s "Please Present Payment" alert with the correct numbers (matching the ones submitted when the button was clicked and those present in the logs), and then it crashes providing the error message:


Cannot read properties of undefined (reading 'toFixed')
TypeError: Cannot read properties of undefined (reading 'toFixed')
at http://localhost:3000/static/js/bundle.js:783:58
at Array.map (<anonymous>)
at App (http://localhost:3000/static.js.bundle.js:768:32)
at renderWithHooks (http://localhost:3000/static/js/bundle.js:22965:22)
at updateFunctionComponent (http://localhost:3000/static/js/buindle.js:27559:20)
at HTMLUnknownElement.callCallback (http://localhost:3000/static/js/bundle.js:12557:18)
at Object.invokeGuardedCallbackDev (http://localhost:3000/static/js/bundle.js:12601:20)
at invokeGuardedcallback (http://localhost:3000/static/js/bundle.js:12658:35)
at beginWork$1 (http://localhost:3000/static/js/bundle.js:32532:11)

This was not occuring before I modified the CalculateRunningTotal function. I’m about 99% sure (as always is the case when I come to get the assistance of the amazing StackOverflow community) that this is simply a case of stupidity where I’m blatantly overlooking something very obvious. My gut instinct tells me it’s related to the way the subtotal state is being reset in the async, but I’m, frankly, terrible at JS. It’s not my bag. If someone could explain my silliness, that would be greatly appreciated.

All related functions:


const logToConsole = (message) => {
    setConsoleLogs((prevLogs) => [...prevLogs, message]);
  };

  useEffect(() => {
    const customConsoleLog = console.log;

    console.log = (message) => logToConsole(message);

    return () => {
      console.log = customConsoleLog;
    };
  }, []);

  const calculateItemTotal = (item) => {
    let sizePrice = getSizePrice(item.size);
    let flavorPrice = item.flavors.length * 0.89;

    return sizePrice + flavorPrice + item.toppingsPrice;
  };

  const calculateRunningTotal = () => {
    let total = 0;
  
    for (const itemTotal of runningTotals) {
      total += itemTotal;
    }
  
    if (selectedDiscount) {
      const discount = discounts.find((discount) => discount.name === selectedDiscount);
      if (discount) {
        const discountMultiplier = 1 - discount.discount;
        total *= discountMultiplier;
      }
    }
  
    // Check if total is NaN before applying toFixed
    return isNaN(total) ? 0 : total.toFixed(2);
  };   

  const handleAddToOrder = () => {
    if (!selectedSize) {
      alert("Select a Size!");
      return;
    }
  
    const item = {
      size: selectedSize,
      flavors: selectedFlavors,
      toppingsPrice: toppingsPrice,
    };
  
    setOrderItems((prevItems) => [...prevItems, item]);
    setSubtotal((prevSubtotal) => prevSubtotal + calculateItemTotal(item));
    setRunningTotals((prevTotals) => [...prevTotals, calculateItemTotal(item)]);
  
    setSelectedSize(null);
    setSelectedFlavors([]);
    setToppingsPrice(0);
    setSyrupToppings((prevToppings) =>
      prevToppings.map((topping) => ({
        ...topping,
        isActive: false,
      }))
    );
  };  

  const getSizePrice = (size) => {
    switch (size) {
      case 'Small':
        return 2.49;
      case 'Medium':
        return 3.29;
      case 'Large':
        return 4.19;
      default:
        return 0;
    }
  };

  const handleAddTopping = (price) => {
    setToppingsPrice((prevPrice) => prevPrice + price);
  };

  const calculateCurrentItem = () => {
    let sizePrice = selectedSize ? getSizePrice(selectedSize) : 0;
    let flavorPrice = selectedFlavors.length * 0.89;
    let total = sizePrice + flavorPrice + toppingsPrice;
  
    if (selectedDiscount) {
      const discount = discounts.find((discount) => discount.name === selectedDiscount);
      if (discount) {
        const discountMultiplier = 1 - discount.discount;
        total *= discountMultiplier;
      }
    }
  
    return total.toFixed(2);
  };

  const handleRemoveOrder = (index) => {
  const removedItem = orderItems[index];
  const removedItemTotal = calculateItemTotal(removedItem);

  setOrderItems((prevItems) => prevItems.filter((_, i) => i !== index));
  setRunningTotals((prevTotals) => prevTotals.filter((_, i) => i !== index));

  setSubtotal((prevSubtotal) => {
    const newSubtotal = prevSubtotal - removedItemTotal;
    return newSubtotal < 0 ? 0 : newSubtotal;
  });
};

  const handlePayNow = async () => {
    if (orderItems.length === 0) {
      alert("No items in the order!"); // Make user select more than 0 items
      return;
    }
  
    let name = prompt("Enter customer name:"); // Prompt for customer name
  
    while (!name) {
      name = prompt("Enter customer name:"); // Re-prompt for customer name
    }
  
    setCustomerName(name); // Set the customer name
    
    // Reset the subtotal
    setSubtotal(0);
  
    let originalTotal = subtotal;
    let discountAmount = 0;
    let discountType = "None"; // Default value for discount type
  
    if (selectedDiscount) {
      const discount = discounts.find((discount) => discount.name === selectedDiscount);
      if (discount) {
        const discountMultiplier = 1 - discount.discount;
        discountAmount = originalTotal - (originalTotal * discountMultiplier);
        originalTotal = originalTotal * discountMultiplier;
        discountType = discount.name; // Store the discount type
      }
    }
  
    const logs = [];
    logs.push('');
    logs.push('');
    logs.push(`Size: ${selectedSize ? selectedSize.charAt(0).toUpperCase() + selectedSize.slice(1) : null}`);
  
    const flavorsText = selectedFlavors.length > 0 ? selectedFlavors.join(", ") : "None";
    logs.push(`Flavors: ${flavorsText}`);
  
    const nonCustomAddIns = syrupToppings.filter((topping) => topping.isActive && !topping.custom);
    const selectedAddIns = nonCustomAddIns.map((topping) => topping.name);
  
    if (selectedAddIns.length > 0) {
      logs.push(`Add-ins: ${selectedAddIns.join(", ")}`);
    } else {
      logs.push("Add-ins: None");
    }
  
    const tax = (originalTotal * 0.056).toFixed(2);
    const totalWithTax = (parseFloat(originalTotal) + parseFloat(tax)).toFixed(2);
  
    logs.push('');
    logs.push(`Subtotal: $${originalTotal.toFixed(2)}`);
    logs.push(`Tax: $${tax}`);
    logs.push(`Total: $${totalWithTax}`);
    logs.push('');
  
    setConsoleLogs(logs); // Update the console logs with the new order information
  
    const updatedToppings = syrupToppings.map((topping) => {
      const updatedTopping = { ...topping };
      if (updatedTopping.isActive) {
        updatedTopping.soldCount += 1;
      }
      updatedTopping.isActive = false;
      return updatedTopping;
    });
  
    setSyrupToppings(updatedToppings);
    setSelectedSize(null); // Reset selectedSize to null
    setSelectedFlavors([]); // Reset selectedFlavors to an empty array
    setToppingsPrice(0); // Reset toppingsPrice to 0
    setSelectedDiscount(null); // Reset selectedDiscount to null
    setRunningTotals([]); // Reset the running total
  
    const soldLogs = syrupToppings
      .filter((topping) => topping.isActive && !topping.custom)
      .map((topping) => {
        return {
          name: topping.name,
          price: topping.price,
          isActive: topping.isActive,
          soldCount: topping.soldCount + 1
        };
      });
  
    const requestOptions = {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(soldLogs)
    };
  
    try {
      const response = await fetch('http://localhost:5000/inventory', requestOptions);
      if (response.ok) {
        // Sold logs successfully updated in the inventory
        console.log('Sold logs updated in the inventory.');
      } else {
        console.error('Failed to update sold logs in the inventory.');
      }
    } catch (error) {
      console.error('Error occurred while updating sold logs in the inventory:', error);
    }
  
    // Send the relevant information to the simulated payment API
    const paymentData = {
      subtotal: originalTotal.toFixed(2),
      tax: tax,
      total: totalWithTax,
      discount: selectedDiscount ? true : false,
      discountAmount: discountAmount.toFixed(2),
      discountType: discountType,
      employee: loginNumberTracking,
    };
  
    try {
      const paymentResponse = await fetch('http://localhost:5000/pay', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(paymentData)
      });
  
      if (paymentResponse.ok) {
        const paymentResult = await paymentResponse.text();
        console.log('Payment API response:', paymentResult);
        if (!selectedDiscount) {
          alert(`Please Present PaymentnSubtotal: ${originalTotal.toFixed(2)}nTax: ${tax}nTotal: ${totalWithTax}`);
        } else {
          alert(`Please Present PaymentnSubtotal: $${originalTotal.toFixed(2)}nDiscount Amount: $${discountAmount.toFixed(2)}nDiscount Type: ${discountType}nTax: $${tax}nTotal (after discount and tax): $${(originalTotal + parseFloat(tax)).toFixed(2)}`);
        }
      } else {
        console.error('Failed to send payment data to the API.');
      }
    } catch (error) {
      console.error('Error occurred while sending payment data to the API:', error);
    }
  };     

  const handleSelectDiscount = (discount) => {
    if (selectedDiscount === discount) {
      setSelectedDiscount(null); // Deselect the currently selected discount
    } else {
      setSelectedDiscount(discount); // Select the clicked discount
    }
  };

StackOverflow is a last resort for me, generally speaking. If I’m here, I’ve been at it for several hours at least. I need someone who knows more than I do; my knowledge isn’t cutting it here.

2

Answers


  1. Chosen as BEST ANSWER

    There it was! The running total is calculated based on the added prices of items in the OrderItems array. Since, despite the RunningTotals array being cleared the OrderItems persisted within the array, this obviously caused a conflict. The OrderItems array needed to be reset BEFORE the RunningTotals array.

    
    setOrderItems([]);
    setRunningTotals([]);
    
    

  2. As the error message says:

    Cannot read properties of undefined (reading ‘toFixed’)

    The error is happening because you’re trying to call toFixed() method of an undefined variable.

    From what you provided, it’s hard to tell correctly which part caused the issue but it could have happened from subtotal not being initialized and used.

    These lines:

        // Reset the subtotal
        setSubtotal(0);
      
        let originalTotal = subtotal;
    

    React state setters are async so if your subtotal is undefined when you run setSubtotal(0), it’s still undefined after running it, until after the next tick, which means originalTotal will also be undefined and thus causing the error by calling originalTotal.toFixed(2).

    If this is not the case, there may be other statements that caused it.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search