I'm pretty new to javascript, and I'm trying to get my totalProfit
to show on my order list page. I keep getting a TypeError: Cannot read properties of undefined (reading 'toFixed') Below I have included what I have. I would really appreciate any help or advice on why I'm having this issue. Thank you!
OrderListScreen.js
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { deleteOrder, listOrders } from '../actions/orderActions';
import LoadingBox from '../components/LoadingBox';
import MessageBox from '../components/MessageBox';
import { ORDER_DELETE_RESET } from '../constants/orderConstants';
export default function OrderListScreen(props) {
const sellerMode = props.match.path.indexOf('/seller') >= 0;
const orderList = useSelector((state) => state.orderList);
const { loading, error, orders } = orderList;
const orderDelete = useSelector((state) => state.orderDelete);
const {
loading: loadingDelete,
error: errorDelete,
success: successDelete,
} = orderDelete;
const userSignin = useSelector((state) => state.userSignin);
const { userInfo } = userSignin;
const dispatch = useDispatch();
useEffect(() => {
dispatch({ type: ORDER_DELETE_RESET });
dispatch(listOrders({ seller: sellerMode ? userInfo._id : '' }));
}, [dispatch, sellerMode, successDelete, userInfo._id]);
const deleteHandler = (order) => {
// TODO: delete handler
if (window.confirm('Are you sure to delete?')) {
dispatch(deleteOrder(order._id));
}
};
return (
<div>
<h1>Orders</h1>
{loadingDelete && <LoadingBox></LoadingBox>}
{errorDelete && <MessageBox variant="danger">{errorDelete}</MessageBox>}
{loading ? (
<LoadingBox></LoadingBox>
) : error ? (
<MessageBox variant="danger">{error}</MessageBox>
) : (
<table className="table">
<thead>
<tr>
<th>ID</th>
<th>USER</th>
<th>DATE</th>
<th>TOTAL</th>
<th>PAID</th>
<th>DELIVERED</th>
<th>SHIPPED</th>
<th>RETURNED</th>
<th>PROFIT</th>
<th>ACTIONS</th>
</tr>
</thead>
<tbody>
{orders.map((order) => (
<tr key={order._id}>
<td>{order._id}</td>
<td>{order.username}</td>
<td>{order.createdAt.substring(0, 10)}</td>
<td>{order.totalPrice.toFixed(2)}</td>
<td>{order.isPaid ? order.paidAt.substring(0, 10) : 'No'}</td>
<td>
{order.isDelivered
? order.deliveredAt.substring(0, 10)
: 'No'}
</td>
<td>
{order.isShipped
? order.ShippedAt.substring(0, 10)
: 'No'}
</td>
<td>
{order.isReturned
? order.ReturnedAt.substring(0, 10)
: 'No'}
</td>
<td>{order.totalProfit.toFixed(2)}</td>
<td>
<button
type="button"
className="small"
onClick={() => {
props.history.push(`/order/${order._id}`);
}}
>
Details
</button>
<button
type="button"
className="small"
onClick={() => deleteHandler(order)}
>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
);
}
PlaceOrderScreen.js
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import {createOrder, } from '../actions/orderActions';
import CheckoutSteps from '../components/CheckoutSteps';
import { ORDER_CREATE_RESET } from '../constants/orderConstants';
import LoadingBox from '../components/LoadingBox';
import MessageBox from '../components/MessageBox';
export default function PlaceOrderScreen(props) {
const cart = useSelector((state) => state.cart);
if (!cart.paymentMethod) {
props.history.push('/payment');
}
const orderCreate = useSelector((state) => state.orderCreate);
const { loading, success, error, order } = orderCreate;
const toPrice = (num) => Number(num.toFixed(2)); // 5.123 => "5.12" => 5.12
cart.itemsPrice = toPrice(
cart.cartItems.reduce((a, c) => a c.qty * c.price, 0)
);
cart.shippingPrice = cart.itemsPrice > 39.99 ? toPrice(0) : toPrice(10);
{
cart.taxPrice = toPrice(0.065 * cart.itemsPrice)}
cart.totalPrice = cart.itemsPrice cart.shippingPrice cart.taxPrice;
//
const toProfit = (num) => Number(num.toFixed(2)); // 5.123 => "5.12" => 5.12
cart.itemsProfit= toProfit(
cart.cartItems.reduce((a, c) => a c.qty * c.profit, 0)
);
cart.totalProfit = cart.itemsProfit;
//
const dispatch = useDispatch();
const placeOrderHandler = () => {
dispatch(createOrder({ ...cart, orderItems: cart.cartItems }));
};
useEffect(() => {
if (success) {
props.history.push(`/order/${order._id}`);
dispatch({ type: ORDER_CREATE_RESET });
}
}, [dispatch, order, props.history, success]);
return (
<div>
<CheckoutSteps step1 step2 step3 step4></CheckoutSteps>
<div className="row top">
<div className="col-2">
<ul>
<li>
<div className="card card-body">
<h2>Order Items</h2>
<ul>
{cart.cartItems.map((item) => (
<li key={item.product}>
<div className="row">
<div>
<img
src={item.image}
alt={item.name}
className="small"
></img>
</div>
<div className="min-30">
<Link to={`/product/${item.product}`}>
{item.name}
</Link>
</div>
<div>
{item.qty} x ${item.price} = ${item.qty * item.price}
</div>
</div>
</li>
))}
</ul>
</div>
</li>
</ul>
</div>
<div className="col-1">
<div className="card card-body">
<ul>
<li>
<h2>Order Summary</h2>
</li>
<li>
<div className="row">
<div>Items</div>
<div>${cart.itemsPrice.toFixed(2)}</div>
</div>
</li>
<li>
<div className="row">
<div>Shipping</div>
<div>${cart.shippingPrice.toFixed(2)}</div>
</div>
</li>
<li>
<div className="row">
<div>Tax</div>
<div>${cart.taxPrice.toFixed(2)}</div>
</div>
</li>
<li>
<div className="row">
<div>
<strong> Order Total</strong>
</div>
<div>
<strong>${cart.totalPrice.toFixed(2)}</strong>
</div>
</div>
</li>
<li>
<button
type="button"
onClick={placeOrderHandler}
className="primary block"
disabled={cart.cartItems.length === 0}
>
Place Order
</button>
</li>
{loading && <LoadingBox></LoadingBox>}
{error && <MessageBox variant="danger">{error}</MessageBox>}
</ul>
</div>
</div>
</div>
</div>
);
}
Backend
OrderModel.js
import mongoose from 'mongoose';
const orderSchema = new mongoose.Schema(
{
orderItems: [
{
name: { type: String, required: true },
qty: { type: Number, required: true },
image: { type: String, required: true },
price: { type: Number, required: true },
profit: { type: Number, required: true },
product: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Product',
required: true,
},
},
],
shippingAddress: {
fullName: { type: String, required: true },
address: { type: String, required: true },
city: { type: String, required: true },
postalCode: { type: String, required: true },
country: { type: String, required: true },
},
paymentMethod: { type: String, required: true },
paymentResult: {
id: String,
status: String,
update_time: String,
email_address: String,
},
itemsPrice: { type: Number, required: true },
shippingPrice: { type: Number, required: true },
taxPrice: { type: Number, required: true },
totalPrice: { type: Number, required: true },
itemsProfit: { type: Number, required: true },
totalProfit: { type: Number, required: true },
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
seller: { type: mongoose.Schema.Types.ObjectID, ref: 'User' },
isPaid: { type: Boolean, default: false },
paidAt: { type: Date },
isDelivered: { type: Boolean, default: false },
isShipped: {type: Boolean, default: false },
isReturned: {type: Boolean, default: false },
deliveredAt: { type: Date },
shippedAt: { type: Date },
ReturnedAt: { type: Date },
},
{
timestamps: true,
}
);
const Order = mongoose.model('Order', orderSchema);
export default Order;
CodePudding user response:
TypeError: Cannot read properties of undefined (reading 'toFixed')
This error's cause is simple literally.
When you use toFixed()
with some variable and that variable is undefined
, that error occurred.
I found toFixed()
in your code a lot but there is no code for undefined
case.
you just add ?
like this
num?.toFixed();
cart?.totalPrice?.toFixed(2)
...
CodePudding user response:
I realized that I was receiving this error because mongodb wasn't registering my totalProfit
variable, so it was being treated as if it was undefined.