Find Value of an array of Object with criterias - reactjs

please help a brother i am new to react i have a demo data that i want to render to my homescreen component
i want to update the data based on the filter result i get so if my filter returns an array of 4 objects,only four object should appear on my screen, but my screen is not updating
this is the home screen as well as the filter function
import React, { useEffect, useState } from 'react'
import {
Container,
CardDeck,
Card,
ListGroup,
Button,
Row,
Col,
Form,
} from 'react-bootstrap'
import Customer from '../cards/Customer'
import { data } from '../../Data'
const HomeScreen = () => {
const [gender, setGender] = useState('All')
const [payment, setPayment] = useState('All')
const [peopleArray, setPeopleArray] = useState([])
const filter = () => {
const newData = data.filter((person) => {
if (gender === 'All' && payment === 'All') {
return person
} else if (gender !== 'All' && payment === 'All') {
return person.Gender === gender
} else if (gender === 'All' && payment !== 'All') {
return person.PaymentMethod === payment
} else if (gender !== 'All' && payment !== 'All') {
return person.PaymentMethod === payment && person.Gender === gender
}
setPeopleArray(newData)
})
console.log('new data', newData)
console.log('peopleArray', peopleArray[0])
console.log('gender!', gender)
console.log('payment!', payment)
}
const submitHandler = (e) => {
e.preventDefault()
filter()
}
const setData = () => {
setPeopleArray(data)
console.log('peopleArray', peopleArray[0])
}
useEffect(() => {
console.log('peopleArray!!', peopleArray[0])
console.log('peopleArray first index', peopleArray[0])
console.log('peopleArray second index', peopleArray[2])
console.log('peopleArray first index of firt', peopleArray[0][0])
}, [peopleArray])
return (
<div className='top'>
<Row>
<Col md={9}>
<h1>All Customers</h1>
<Container>
<CardDeck className=' bg-secondary'>
<Customer data={peopleArray[0]} />
</CardDeck>
</Container>
</Col>
<Col md={3} className='fix'>
<div>
<h4>
<strong>Sort by:</strong>
</h4>
<Card>
<Form onSubmit={submitHandler}>
<ListGroup variant='flush'>
<ListGroup.Item>
<Row>
<Col>
<Form.Label>Gender</Form.Label>
</Col>
<Col>
<Form.Group>
<Form.Control
as='select'
value={gender}
onChange={(e) => setGender(e.target.value)}
>
<option>All</option>
<option>Male</option>
<option>Female</option>
<option>Prefer to skip</option>
</Form.Control>
</Form.Group>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>
<Form.Label>Payment</Form.Label>
</Col>
<Col>
<Form.Group>
<Form.Control
as='select'
value={payment}
onChange={(e) => setPayment(e.target.value)}
>
<option>All</option>
<option>check</option>
<option>money order</option>
<option>paypal</option>
</Form.Control>
</Form.Group>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Button className='btn-block' type='submit'>
Filter
</Button>
</ListGroup.Item>
</ListGroup>
</Form>
</Card>
</div>
</Col>
</Row>
</div>
)
}
export default HomeScreen

You are calling setPeopleArray in array filter method. what you need to do is call it outside array filter method. if any of the condition above it evaluates to true the function would return and your setter would not be called. Here is something you can do. Also array filter expects you to return true or false (true means keep that element false means filter it out).
const filter = () => {
const newData = data.filter((person) => {
if (gender === 'All' && payment === 'All') {
return person
} else if (gender !== 'All' && payment === 'All') {
return person.Gender === gender
} else if (gender === 'All' && payment !== 'All') {
return person.PaymentMethod === payment
} else if (gender !== 'All' && payment !== 'All') {
return person.PaymentMethod === payment && person.Gender === gender
}
})
setPeopleArray(newData)
}

Related

Selecting all check boxes of one group when select all is clicked in React

I am showing permissions for my project in an accordion which whose title is the group from which the permission belongs, I have put select all checkbox in each accordion now I want to check the select all checkbox and all the check boxes in that accordion only gets selected and their ids being pushed in the array which will be then passed to PHP API. Here is the code:
const Add_AssignPermission = () => {
const [permissionData, setPermissionData] = useState([])
const [roleData, setRoleData] = useState([])
const [selectedRole, setSelectedRole] = useState('')
const [selectedPermission, setSelectedPermission] = useState('')
const [checkPermission, setCheckedPermission] = useState([])
const { role_id } = useParams()
function getPermissionData() {
const url = '/permission?length=10000'
axios.get(url)
.then((response) => {
console.log(response)
setPermissionData(response.data.data.data)
setSelectedPermission(response.data.data.data[0].id)
})
.catch((err) => console.log(err))
}
function getRoleData() {
const url = '/roles'
axios.get(url)
.then((response) => {
console.log(response)
setRoleData(response.data.data.data)
setSelectedRole(response.data.data.data[0].id)
})
.catch((err) => console.log(err))
}
const [successMessage, setSuccessMessage] = useState(null)
useEffect(() => {
getPermissionData()
getRoleData()
}, [])
useEffect(() => {
window.scrollTo(0, 0)
}, [successMessage])
const resetForm = () => {
setPermissionData("")
setRoleData("")
}
function submit(event, errors, values) {
event.preventDefault()
if (errors.length < 1) {
const body = {
checkedPermission: checkPermission
}
const config = {
method: 'post',
url: `/assignPermissiontoRole/${role_id}`,
headers: AuthHeader(),
data: body
}
console.log(config)
axios(config)
// const response = axios.post(`/assignPermissiontoRole/${role_id}`, checkPermission)
// console.log(response)
.then(function (response) {
console.log(response)
setSuccessMessage("Permissions Assigned Successfully")
getPermissionData()
getRoleData()
})
.catch(function (error) {
console.log(error)
setSuccessMessage(null)
})
}
}
return (
<>
<Card>
<CardHeader>
<CardTitle tag="h4">Assign A New Permission to Role</CardTitle>
</CardHeader>
{/* {successMessage && <Alert> {successMessage}</Alert>}
<AvForm
onSubmit={(event, errors, values) => submit(event, errors, values)
}
>
<Row>
<Col sm ='12' md='6'>
<Row>
<Col sm='6'>
<AvGroup>
<Label> Permission Name </Label>
<AvInput
name="permission"
id="permission"
type = "select"
onChange={(e) => setSelectedPermission(e.target.value)}
required
value = {selectedPermission}
>
{permissionData.map((value, key) => {
// let permissionName = properCase(value.name, '-')
// permissionName = properCase(permissionName, '_')
return (
<option value={value.id} key={key}>
{value.name}
</option>
)
})}
</AvInput>
<AvFeedback>Please enter a Permission!</AvFeedback>
</AvGroup>
</Col>
<Col sm='6'>
<AvGroup>
<Label> Role Name </Label>
<AvInput
name="role"
id="role"
type = "select"
onChange={(e) => setSelectedRole(e.target.value)}
required
value = {selectedRole}
>
{roleData.map((value, key) => {
const roleName = properCase(value.name, '_')
return (
<option value={value.id} key={key}>
{roleName}
</option>
)
})}
</AvInput>
<AvFeedback>Please enter a Role!</AvFeedback>
</AvGroup>
</Col>
</Row>
</Col>
<Col sm ='12' md='6' className = 'align-self-center mt-75'>
<AvGroup className="d-flex mb-0">
<Button.Ripple
className="mr-1"
color="primary"
type="submit"
>
Submit
</Button.Ripple>
<Button outline color='secondary' onClick={resetForm}>
Reset
</Button>
</AvGroup>
</Col>
</Row>
</AvForm> */}
{successMessage && <Alert> {successMessage}</Alert>}
</Card>
<Row>
<Col sm="12">
<AvForm onSubmit={(event, errors, values) => submit(event, errors, values)} >
{permissionData.map((ele) => {
return (
<Accordion title={ele.group_name} Open={true} key={ele.group_name}>
<Row>
<Col sm='3'>
<AvGroup>
<AvInput type='checkbox' name='select_all_checkbox' id='select_all_checkbox'
//onChange={handleChange}
onChange={(e) => {
if (e.target.checked) {
ele.grouped_permissions.map((permissions) => {
setCheckedPermission([
...checkPermission,
{
id: permissions.permission_id
}
])
})
console.log(checkPermission)
} else {
console.log("IN ELSE")
}
}}
/>
{console.log(checkPermission)}
<Label for='decimal_point_in_valueVertical'>Select All</Label>
</AvGroup>
{/* <AvGroup>
<AvInput type='checkbox' name='select_all_checkbox' id='select_all_checkbox'
//onChange={handleChange}
onChange={(e) => {
if (e.target.checked) {
ele.grouped_permissions.map((permissions) => {
setCheckedPermission([
...checkPermission,
{
id: permissions.permission_id
}
])
})
console.log(checkPermission)
} else {
console.log("IN ELSE")
}
}}
/>
{console.log(checkPermission)}
<Label for='decimal_point_in_valueVertical'>Select All</Label>
</AvGroup> */}
</Col>
{ele.grouped_permissions.map((ele2) => {
return (
<Col sm='3' key={ele2.permissions.name}>
<AvGroup>
<AvInput type='checkbox' name='permission_checkbox' id='permission_checkbox'
//key={ele2.permissions.name}
onChange={(e) => {
console.log(e.target)
if (e.target.checked) {
setCheckedPermission([
...checkPermission,
{
// id: ele2.permissions.id
id: ele2.permissions.id
}
])
//console.log(checkPermission)
} else {
setCheckedPermission(
checkPermission.filter((checkedBox) => checkedBox.id !== ele2.permissions.id)
)
}
}}
data={ele2.permissions.id}
value={checkPermission}
/>
<Label for='decimal_point_in_valueVertical'>{ele2.permissions.name}</Label>
{/* <AvInput type='text' name='mask_name' id='mask_name' placeholder='mask_name'
/> */}
</AvGroup>
</Col>
)
})}
</Row>
</Accordion>
)
})}
<Col sm='12'>
<AvGroup className='d-flex mb-0 float-right'>
<Button.Ripple className='mr-1' color='primary' type='submit' >
Assign Permission
</Button.Ripple>
</AvGroup>
</Col>
</AvForm>
</Col>
</Row>
</>
)
}
export default Add_AssignPermission
I have tried multiple things but nothing worked for me. In the above code snippet I was trying to push that group values into the state using map but when I consoled it contains only the last permission id in the accordion. PLEASE HELP !!!!

Can't add product into Cart

Unable to add product into the cart although, the url is getting changed, it showing two errors in the console, cant understand what is wrong.
http://localhost:3000/cart/636d4264ff92e60977f3bb4a?qt=3
636d4264ff92e60977f3bb4a = productID and qt=3 quantity
enter image description here
here are my files
import React, { useEffect } from 'react'
import { Link, useParams, useLocation, useNavigate } from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'
import { Row, Col, ListGroup, Image, Form, Button, Card } from 'react-bootstrap'
import Message from '../components/Message'
import { addToCart, removeFromCart } from '../actions/cartActions'
const CartScreen = ({match, history}) => {
const {id} = useParams();
//const productId = match.params.id
const location = useLocation();
const qty = location.search ? Number (location.search.split('=') [1]) : 1
const dispatch = useDispatch()
const navigate = useNavigate()
const cart = useSelector((state) => state.cart)
const { cartItems } = cart
useEffect(() => {
if(id){
//useEffect working fine
dispatch(addToCart(id,qty))
}else{
//console.log('useEffect error')
}
}, [dispatch, id, qty])
const removeFromCartHandler = (id) => {
dispatch(removeFromCart(id))
}
const chechoutHandler = () => {
navigate('/login?redirect=/shipping')
}
return (
<Row>
<Col md={8}>
<h1>Shopping Cart</h1>
{ cartItems && cartItems.length === 0 ? (
<Message> Your cart is empty <Link to='/'>Go Back</Link></Message>
) : (
<ListGroup variant='flush'>
{cartItems.map(item => (
<ListGroup.Item key={item.product}>
<Row>
<Col md={2}>
<Image src={item.image} alt={item.name} className="cartItemPhoto" flude rounded />
</Col>
<Col md={3}>
<Link to={`/product/${item.product}`}>{item.name}</Link>
</Col>
<Col md={2}>₹{item.price}</Col>
<Col md={2}>
<Form.Control
as='select'
value={item.qty}
onChange={(e)=> dispatch(addToCart(item.product,Number(e.target.value)))}
>
{[...Array(item.countInStock).keys()].map((x) => (
<option key={x+1} value={x + 1}>
{ x + 1 }
</option>
))}
</Form.Control>
</Col>
<Col md={2}>
<Button type='button' varient='ligth' onClick={() => removeFromCartHandler(item.product)} >
<i className='fas fa-trash'></i>
</Button>
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
)}
</Col>
<Col md={4}>
<Card>
<ListGroup varient = 'flush'>
<ListGroup.Item>
<h2>Subtotal ({cartItems.reduce((acc,item)=>acc+item.qty,0)}) items</h2>
₹{cartItems.reduce((acc,item)=>acc+item.qty * item.price,0).toFixed(2)}
</ListGroup.Item>
<ListGroup>
<Button type='button' className='btn-block' disabled={cartItems.length === 0} onClick={chechoutHandler}>
Proceed To Checkout
</Button>
</ListGroup>
</ListGroup>
</Card>
</Col>
</Row>
)
}
export default CartScreen
import React, { useState, useEffect } from 'react'
import { Link, useParams} from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'
import {Row, Col, Image, ListGroup, Card, Button, Form } from 'react-bootstrap'
import Rating from '../components/Rating'
import Loader from '../components/Loader'
import Message from '../components/Message'
import { listProductDetails, createProductReview } from '../actions/productActions'
import { useNavigate } from 'react-router-dom'
//import products from '../../../backend/data/products.js'
//import axios from 'axios'
import { PRODUCT_CREATE_REVIEW_RESET } from '../constants/productConstants'
const ProductScreen = ({ match}) => {
const {id} = useParams();
//const product = products.find((p) => p._id === id);
const [qty, setQty] = useState(1)
const [rating, setRating] = useState(0)
const [comment, setComment] = useState('')
const dispatch = useDispatch()
const productDetails = useSelector(state => state.productDetails)
const { loading, error, product } = productDetails
//console.log(product)
// reviews aasche sudhu
const userLogin = useSelector((state) => state.userLogin)
const { userInfo } = userLogin
const productReviewCreate = useSelector((state) => state.productReviewCreate)
const {
success: successProductReview,
loading: loadingProductReview,
error: errorProductReview,
} = productReviewCreate
useEffect(()=>{
if(successProductReview){
alert('Review Submitted!')
setRating(0)
setComment('')
dispatch({type: PRODUCT_CREATE_REVIEW_RESET})
}
dispatch(listProductDetails(id))
}, [dispatch, id, successProductReview])
//if(!product) return null;
// return ( <div>{product.name}</div> );
const history = useNavigate()
const addToCartHandler = () =>{
history(`/cart/${id}?qt=${qty}`)
}
const submitHandler = (e) => {
e.preventDefault()
dispatch(
createProductReview(id, {
rating,
comment,
})
)
}
//console.log(product)
return (
<>
<Link className='btn btn-outline-primary' to='/'>
Go Back
</Link>
{ loading ? (
<Loader/>
): error ? (
<Message variant='danger'> {error} </Message>
) : (
<>
<Row>
<Col md={6}>
{/* src={product.image} changed to -> {`${window.location.origin}/${product.image.name}`} */}
<Image src= {product.image} alt={product.name} fluid/>
</Col>
<Col md={3}>
<ListGroup variant='flust'>
<ListGroup.Item>
<h3>{product.name}</h3>
</ListGroup.Item>
<ListGroup.Item>
{/*
<Rating
value={product.rating.toString()}
text={product.numReviews}
/>
*/}
</ListGroup.Item>
<ListGroup.Item>
Price: ₹{product.price}
</ListGroup.Item>
<ListGroup.Item>
Description: {product.description}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={3}>
<Card>
<ListGroup variant='flush'>
<ListGroup.Item>
<Row>
<Col>
Price:
</Col>
<Col>
<strong>₹{product.price}</strong>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>
Status:
</Col>
<Col>
{product.countInStock>0 ? 'In Stock' : 'Out Of Stock'}
</Col>
</Row>
</ListGroup.Item>
{ product.countInStock > 0 && (
<ListGroup.Item>
<Row>
<Col>Qty</Col>
<Col>
<Form.Control
as='select'
value={qty}
onChange={(e)=>setQty(e.target.value)}
>
{[...Array(product.countInStock).keys()].map((x) => (
<option key={x+1} value={x + 1}>
{ x + 1 }
</option>
))}
</Form.Control>
</Col>
</Row>
</ListGroup.Item>
)}
<ListGroup.Item>
<Button
onClick={addToCartHandler}
className='btn btn-success btn-block btn-wd'
type='button'
disabled={product.countInStock===0}
>
Add To Cart
</Button>
</ListGroup.Item>
</ListGroup>
</Card>
</Col>
</Row>
<Col md={6}>
<h2>Reviews</h2>
{product.reviews.length === 0 && <Message>No Reviews</Message>}
<ListGroup variant='flush'>
{product.reviews.map((review) => (
<ListGroup.Item key={review._id}>
<strong>{review.name}</strong>
<Rating value={review.rating} />
<p>{review.createdAt.substring(0, 10)}</p>
<p>{review.comment}</p>
</ListGroup.Item>
))}
<ListGroup.Item>
<h2>Write a Customer Review</h2>
{successProductReview && (
<Message variant='success'>
Review submitted successfully
</Message>
)}
{loadingProductReview && <Loader />}
{errorProductReview && (
<Message variant='danger'>{errorProductReview}</Message>
)}
{userInfo ? (
<Form onSubmit={submitHandler}>
<Form.Group controlId='rating'>
<Form.Label>Rating</Form.Label>
<Form.Control
as='select'
value={rating}
onChange={(e) => setRating(e.target.value)}
>
<option value=''>Select...</option>
<option value='1'>1 - Poor</option>
<option value='2'>2 - Fair</option>
<option value='3'>3 - Good</option>
<option value='4'>4 - Very Good</option>
<option value='5'>5 - Excellent</option>
</Form.Control>
</Form.Group>
<Form.Group controlId='comment'>
<Form.Label>Comment</Form.Label>
<Form.Control
as='textarea'
row='3'
value={comment}
onChange={(e) => setComment(e.target.value)}
></Form.Control>
</Form.Group>
<Button
disabled={loadingProductReview}
type='submit'
variant='primary'
>
Submit
</Button>
</Form>
) : (
<Message>
Please <Link to='/login'>sign in</Link> to write a review{' '}
</Message>
)}
</ListGroup.Item>
</ListGroup>
</Col>
</>
)}
</>
)
}
// Form.Control e add chilo, onChange{(e) => setQty(e.target.value)}
/*
<Form.Control
as='select'
value={qty}
onChange{(e) => setQty(e.target.value)}
>
// lec 32
*/
export default ProductScreen
import axios from 'axios'
import {
CART_ADD_ITEM,
CART_REMOVE_ITEM,
CART_SAVE_SHIPING_ADDRESS,
CART_SAVE_PAYMENT_METHOD
} from '../constants/cartConstants'
import { useParams } from 'react-router-dom'
export const addToCart = (id, qty) => async (dispatch, getState) => {
const {id} = useParams();
//console.log(`id working = ${id}`)
const { data } = await axios.get(`/api/products/${id}`)
//console.log(`data = ${data}`)
dispatch({
type: CART_ADD_ITEM,
payload: {
product: data._id,
name: data.name,
image: data.image,
price: data.price,
countInStock: data.countInStock,
qty,
},
})
localStorage.setItem('cartItems', JSON.stringify(getState().cart.cartItems))
}
export const removeFromCart = (id) => (dispatch, getState) => {
dispatch({
type: CART_REMOVE_ITEM,
payload: id
})
localStorage.setItem('cartItems',JSON.stringify(getState().cart.cartItems))
}
export const saveShippingAdderss = (data) => (dispatch) => {
dispatch({
type: CART_SAVE_SHIPING_ADDRESS,
payload: data,
})
localStorage.setItem('shippingAddress',JSON.stringify(data))
}
export const savePaymentMethod = (data) => (dispatch) => {
dispatch({
type: CART_SAVE_PAYMENT_METHOD,
payload: data,
})
localStorage.setItem('paymentMethod',JSON.stringify(data))
}
import { CART_ADD_ITEM, CART_REMOVE_ITEM, CART_SAVE_PAYMENT_METHOD, CART_SAVE_SHIPING_ADDRESS } from '../constants/cartConstants.js'
import { PRODUCT_DETAILS_REQUEST, PRODUCT_LIST_REQUEST } from '../constants/productConstants.js'
export const cartReducer = (
state = { cartItems: [], shippingAddress: {} }, action) => {
//console.log(`action.type line on 6 = ${action.type}`)
switch(action.type){
case CART_ADD_ITEM:
//console.log(`CART_ADD_ITEM 3333 = ${action.type}`)
const item = action.payload
const existItem = state.cartItems.find( (x) => x.product === item.product)
if(existItem){
return {
...state,
cartItems: state.cartItems.map ((x) =>
x.product === existItem.product ? item : x
),
}
} else {
return {
...state,
cartItems: [...state.cartItems, item],
}
}
case CART_REMOVE_ITEM:
return {
...state,
cartItems: state.cartItems.filter((x) => x.product !==action.payload),
}
case CART_SAVE_SHIPING_ADDRESS:
return {
...state,
shippingAddress: action.payload,
}
case CART_SAVE_PAYMENT_METHOD:
return {
...state,
paymentMethod: action.payload,
}
default:
return state
}
}
I want to resolve the error so that I can add products to my cart. Thank you

A state mutation was detected between dispatches

I've got this issue which I do not understand. I am getting an invariant error that says a state mutation has occurred, but at a very awkward place.
Basically I've got this page:
import React, { useState, useEffect } from "react";
import {
Link,
useLocation,
useNavigate,
useSearchParams,
} from "react-router-dom";
import { Form, Button, Row, Col, Table } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
import { useDispatch, useSelector } from "react-redux";
import Loader from "../components/Loader";
import Message from "../components/Message";
import FormContainer from "../components/FormContainer";
import { register } from "../actions/userActions";
import { getUserDetails, updateUserProfile } from "../actions/userActions";
import { USER_UPDATE_PROFILE_RESET } from "../constants/userConstants";
import { listMyOrders } from "../actions/orderActions";
function ProfileScreen() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [message, setMessage] = useState("");
const dispatch = useDispatch();
const location = useLocation();
const userDetails = useSelector((state) => state.userDetails);
const navigate = useNavigate();
const { error, loading, user } = userDetails;
const userLogin = useSelector((state) => state.userLogin);
const { userInfo } = userLogin;
const userUpdateProfile = useSelector((state) => state.userUpdateProfile);
const { success } = userUpdateProfile;
const orderListMy = useSelector((state) => state.orderListMy);
const { loading: loadingOrders, error: errorOrders, orders } = orderListMy;
useEffect(() => {
if (!userInfo) {
navigate("/login");
} else {
if (!user || !user.name || success) {
dispatch({ type: USER_UPDATE_PROFILE_RESET });
dispatch(getUserDetails("profile"));
dispatch(listMyOrders());
} else {
setName(user.name);
setEmail(user.email);
}
}
}, [dispatch, location, userInfo, user, success]);
const submitHandler = (e) => {
e.preventDefault();
if (password != confirmPassword) {
setMessage("Passwords do not match!");
} else {
dispatch(
updateUserProfile({
id: user._id,
name: name,
email: email,
password: password,
})
);
}
};
return (
<Row>
<Col md={3}>
<h2>User Profile</h2>
{message && <Message variant="danger">{message}</Message>}
{error && <Message variant="danger">{error}</Message>}
{loading && <Loader></Loader>}
<Form onSubmit={submitHandler}>
<Form.Group controlId="name">
<Form.Label>Name</Form.Label>
<Form.Control
required
type="name"
placeholder="Enter Name"
value={name}
onChange={(e) => setName(e.target.value)}
></Form.Control>
</Form.Group>
<Form.Group controlId="email">
<Form.Label>Email Address</Form.Label>
<Form.Control
required
type="email"
placeholder="Enter Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
></Form.Control>
</Form.Group>
<Form.Group controlId="password">
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
placeholder="Enter Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
></Form.Control>
</Form.Group>
<Form.Group controlId="passwordConfirm">
<Form.Label>Confirm Password</Form.Label>
<Form.Control
type="password"
placeholder="Confirm Password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
></Form.Control>
</Form.Group>
<Button type="submit" variant="primary">
Update
</Button>
</Form>
</Col>
<Col md={9}>
<h2>My Orders</h2>
{loadingOrders ? (
<Loader />
) : errorOrders ? (
<Message variant="danger">{errorOrders}</Message>
) : (
<Table striped responsive className="table-sm">
<thead>
<tr>
<th>ID</th>
<th>Date</th>
<th>Total</th>
<th>Paid</th>
<th>Delivered</th>
<th></th>
</tr>
</thead>
<tbody>
{orders.map((order) => (
<tr key={order._id}>
<td>{order._id}</td>
<td>{order.createdAt.substring(0, 10)}</td>
<td>${order.totalPrice}</td>
<td>
{order.isPaid ? (
order.paidAt.substring(0, 10)
) : (
<i className="fas fa-times" style={{ color: "red" }}></i>
)}
</td>
<td>
<LinkContainer to={`/order/${order._id}`}>
<Button className="btn-sm">Details</Button>
</LinkContainer>
</td>
</tr>
))}
</tbody>
</Table>
)}
</Col>
</Row>
);
}
export default ProfileScreen;
and in this page whenever you click on the Details button on some of the orders you get redirected to this page:
import React, { useState, useEffect } from "react";
import { Button, Row, Col, ListGroup, Image, Card } from "react-bootstrap";
import { Link, useNavigate, useParams } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { PayPalButton } from "react-paypal-button-v2";
import Message from "../components/Message";
import Loader from "../components/Loader";
import CheckoutSteps from "../components/CheckoutSteps";
import {
createOrder,
getOrderDetails,
payOrder,
} from "../actions/orderActions";
import {
ORDER_CREATE_RESET,
ORDER_PAY_RESET,
} from "../constants/orderConstants";
function OrderScreen() {
const orderDetails = useSelector((state) => state.orderDetails);
const { order, error, loading } = orderDetails;
const orderPay = useSelector((state) => state.orderPay);
const { loading: loadingPay, success: successPay } = orderPay;
const dispatch = useDispatch();
const history = useNavigate();
const orderId = useParams();
const takenId = orderId.id;
const [sdkReady, setSdkReady] = useState(false);
const cart = useSelector((state) => state.cart);
let copyCart = Object.assign({}, cart);
if (!loading && !error) {
order.itemsPrice = order.orderItems
.reduce((acc, item) => acc + item.price * item.qty, 0)
.toFixed(2);
}
const addPayPalScript = () => {
const script = document.createElement("script");
script.type = "text/javascript";
script.src =
"https://www.paypal.com/sdk/js?client-id=ATMiiNcpLBRgha0mQCRpS5GJRC9YrATzPxyLFvWGoVsCvoxg46E0UGielBSPptskQWiqk8mrp2eQgpnC";
script.async = true;
script.onload = () => {
setSdkReady(true);
};
document.body.appendChild(script);
};
useEffect(() => {
if (!order || successPay || order._id !== Number(takenId)) {
dispatch({ type: ORDER_PAY_RESET });
dispatch(getOrderDetails(takenId));
} else if (!order.isPaid) {
if (!window.paypal) {
addPayPalScript();
} else {
setSdkReady(true);
}
}
}, [dispatch, order, orderId, successPay]);
const successPaymentHandler = (paymentResult) => {
dispatch(payOrder(takenId, paymentResult));
};
return loading ? (
<Loader />
) : error ? (
<Message variant="danger">{error}</Message>
) : (
<div>
<h1>Order: {order._id}</h1>
<Row>
<Col md={8}>
<ListGroup variant="flush">
<ListGroup.Item>
<h2>Shipping</h2>
<p>
<strong>Name: </strong>
{order.user.name}
</p>
<p>
<strong>Email: </strong>
<a href={`mailto:${order.user.email}`}>{order.user.email}</a>
</p>
<p>
<strong>Shipping: </strong>
{order.shippingAddress.address}, {order.shippingAddress.city}
{" "}
{order.shippingAddress.postalCode},{" "}
{order.shippingAddress.country}
</p>
{order.isDelivered ? (
<Message variant="success">
Delivered on {order.deliveredAt}
</Message>
) : (
<Message variant="warning">Not Delivered</Message>
)}
</ListGroup.Item>
<ListGroup.Item>
<h2>Payment Method</h2>
<p>
<strong>Method: </strong>
{order.paymentMethod}
</p>
{order.isPaid ? (
<Message variant="success">Paid on {order.paidAt}</Message>
) : (
<Message variant="warning">Not Paid</Message>
)}
</ListGroup.Item>
<ListGroup.Item>
<h2>Order Items</h2>
{order.orderItems.length === 0 ? (
<Message variant="info">Your order is empty</Message>
) : (
<ListGroup variant="flush">
{order.orderItems.map((item, index) => (
<ListGroup.Item key={index}>
<Row>
<Col md={1}>
<Image
src={item.image}
alt={item.name}
fluid
rounded
/>
</Col>
<Col>
<Link to={`/product/${item.product}`}>
{item.name}
</Link>
</Col>
<Col md={4}>
{item.qty} X ${item.price} = $
{(item.qty * item.price).toFixed(2)}
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
)}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={4}>
<Card>
<ListGroup variant="flush">
<ListGroup.Item>
<h2>Order Summary</h2>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Items:</Col>
<Col>${order.itemsPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Shipping:</Col>
<Col>${order.shippingPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Tax:</Col>
<Col>${order.taxPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Total:</Col>
<Col>${order.totalPrice}</Col>
</Row>
</ListGroup.Item>
{!order.isPaid && (
<ListGroup.Item>
{loadingPay && <Loader />}
{!sdkReady ? (
<Loader />
) : (
<PayPalButton
amount={order.totalPrice}
onSuccess={successPaymentHandler}
/>
)}
</ListGroup.Item>
)}
</ListGroup>
</Card>
</Col>
</Row>
</div>
);
}
export default OrderScreen;
Here everything works perfectly fine, but when you decide to go from this page to the Home page:
import React, { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Row, Col } from "react-bootstrap";
import Product from "../components/Product";
import Loader from "../components/Loader";
import Message from "../components/Message";
import { listProducts } from "../actions/productActions";
function HomeScreen() {
const dispatch = useDispatch();
const productList = useSelector((state) => state.productList);
const { error, loading, products } = productList;
useEffect(() => {
dispatch(listProducts());
}, [dispatch]);
return (
<div>
<h1>Latest Products</h1>
{loading ? (
<Loader />
) : error ? (
<Message variant="danger">{error}</Message>
) : (
<Row>
{products.map((product) => (
<Col key={product._id} sm={12} md={6} lg={4} xl={3}>
<Product product={product} />
</Col>
))}
</Row>
)}
</div>
);
}
export default HomeScreen;
You get the Invariant failed error at line 13, where I'm trying to dispatch the listProducts method.
I've had a situation with this error not so long ago, managed to fix it because I used to update a state directly. I understand why I used to get that error before, but this time I am way more confused than before, because this time I am literally not touching any value anywhere along the state, I am just displaying it. I've checked the backend and I get no errors there, meaning this is strictly a React problem. I do not understand why the problem is occurring only when I am trying to go from details to the home screen.

state.cartItems is not iterable

I am new to react. I am not able to figure out the solution. On adding a product to the cart I am not able to see it in the cart scree. Please suggest any changes. The error I am getting is : state.cartItems is not iterable (cartReducers.js:26).
CART ACTION:
const { data } = await axios.get(`/api/products/${id}`)
console.log(data);
dispatch({
type: CART_ADD_ITEM,
payload: {
product: data._id,
name: data.name,
image: data.image,
price: data.price,
countInStock: data.countInStock,
qty,
},
})
console.log(data);
console.log(getState().cart.cartItems)
localStorage.setItem('cartItems', JSON.stringify(getState().cart.cartItems))
}
REDUCER:
export const cartReducer = (
state = { cartItems: []},
action
) => {
switch (action.type) {
case CART_ADD_ITEM:
const item = action.payload
const existItem = state.cartItems?.find((x) => x.product === item.product)
if (existItem) {
return {
...state.cartItems,
cartItems: state.cartItems?.map((x) =>
x.product === existItem.product ? item : x
),
}
} else {
return {
...state.cartItems,
cartItems: [...state.cartItems, item],
}
}
case CART_REMOVE_ITEM:
return {
...state.cartItems,
cartItems: state.cartItems.filter((x) => x.product !== action.payload),
}
default:
return state
}
}
Below is the cart component. I want to access all the cart items and calculate total quantity and price.
CART COMPONENT:
import React, { useEffect } from 'react'
import { Link } from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'
import { Row, Col, ListGroup, Image, Form, Button, Card } from 'react-bootstrap'
import Message from '../components/Message'
import { addToCart, removeFromCart } from '../actions/cartActions'
const CartScreen = ({ match, location, history }) => {
const productId = match.params.id
const qty = location.search ? Number(location.search.split('=')[1]) : 1
const dispatch = useDispatch()
const cart = useSelector((state) => state.cart)
const { cartItems } = cart
useEffect(() => {
if (productId) {
dispatch(addToCart(productId, qty))
}
}, [dispatch, productId, qty])
const removeFromCartHandler = (id) => {
dispatch(removeFromCart(id))
}
return (
<Row>
<Col md={8}>
<h1>Shopping Cart</h1>
{cartItems?.length === 0 ? (
<Message>
Your cart is empty <Link to='/'>Go Back</Link>
</Message>
) : (
<ListGroup variant='flush'>
{cartItems?.map((item) => (
<ListGroup.Item key={item.product}>
<Row>
<Col md={2}>
<Image src={item.image} alt={item.name} fluid rounded />
</Col>
<Col md={3}>
<Link to={`/product/${item.product}`}>{item.name}</Link>
</Col>
<Col md={2}>${item.price}</Col>
<Col md={2}>
<Form.Control
as='select'
value={item.qty}
onChange={(e) =>
dispatch(
addToCart(item.product, Number(e.target.value))
)
}
>
{[...Array(item.countInStock).keys()]?.map((x) => (
<option key={x + 1} value={x + 1}>
{x + 1}
</option>
))}
</Form.Control>
</Col>
<Col md={2}>
<Button
type='button'
variant='light'
onClick={() => removeFromCartHandler(item.product)}
>
<i className='fas fa-trash'></i>
</Button>
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
)}
</Col>
<Col md={4}>
<Card>
<ListGroup variant='flush'>
<ListGroup.Item>
<h2>
Subtotal ({cartItems?.reduce((acc, item) => acc + item.qty, 0)})
items
</h2>
Rs.
{cartItems?.reduce((acc, item) => acc + item.qty * item.price, 0)
.toFixed(2)}
</ListGroup.Item>
</ListGroup>
</Card>
</Col>
</Row>
)
}
export default CartScreen

Fetch all Names in Option Value, but getting only 1

I am getting array of objects on props.items. How to show all the name from props.items.name in option select? What is happening now is : I am only fetching Name for selected user but not getting all the users and select any choice. I am new to reactjs. Can anyone help me out yrr. Thanks in advance.
import { useEffect, useState } from 'react';
import { Button, Container, Row, Col, Form, Modal } from 'react-bootstrap';
import configData from './../../config/constant.json'
const TransferDialog = (props) => {
let [transferDiv, showtransferDiv] = useState(false)
let [deleteDiv, showDeleteDiv] = useState(false)
let [confirmDiv, showConfirmDiv] = useState(true);
let [error, setError] = useState(false);
let [pending, setPending] = useState(false);
let [permission, setPermission] = useState();
const [userDetails, setUserDetails] = useState([])
const [radio, setradio] = useState([])
let dropdownvalue;
useEffect(()=>{
console.log(props.items);
}, [])
function dropDown(value) {
dropdownvalue = value;
console.log("Dropdown", dropdownvalue);
}
function onChangeValue(event) {
console.log(radio);
}
function handleDelete() {
console.log("Id-->", props.userid);
const abortCont = new AbortController();
console.log("Dropdown", dropdownvalue, radio);
let data = {
id: dropdownvalue,
target: props.userid,
radio: radio
}
fetch(`${configData.SERVER_URL}/admin/deleteuser`, {
credentials: configData.COOKIES_CONFIG,
signal: abortCont.signal,
method: 'post',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
})
.then(res => {
if (!res.ok) {
throw Error('Something Went Wrong')
}
return res.json()
})
.then(res_data => {
if (res_data.status == false) {
throw Error(res_data.message)
} else {
setPending(false);
}
})
.catch(err => {
if (abortCont === "AbortError") {
} else {
setError(err.message);
setPending(false);
}
})
}
function handleYes() {
showConfirmDiv(false);
showDeleteDiv(true);
}
return (
<div>
<Modal
size="lg"
aria-labelledby="contained-modal-title-vcenter"
centered
show={props.show}
onHide={props.onHide}
>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">
Delete User
</Modal.Title>
</Modal.Header>
<Modal.Body>
{
confirmDiv
&&
<>
<h4>Do you really want to delete ??</h4>
</>
}
{
deleteDiv &&
<div onChange={onChangeValue}>
<p>Do you want to transfer user data to another user??</p>
<input type="radio" value="Yes" name="Yes" onChange={() => showtransferDiv(true) || setradio(true)} />
<label >Yes</label>
<input type="radio" value="No" name="Yes" onChange={() => showtransferDiv(false) || setradio(false) } />
<label >No</label><br />
</div>
}
{
transferDiv &&
<Form>
<Form.Group className="mb-3">
<Row>
<Col>
<Form.Group className="mb-3">
</Form.Group>
</Col>
<Col>
<Form.Select onChange={(e) => dropDown(e.target.value)}>
<option value={props.items._id} >{props.items.name}</option>
</Form.Select>
</Col>
</Row>
</Form.Group>
<Form.Text className="text-muted">
</Form.Text>
</Form>
}
{
pending && <p>Pending...</p>
}
{
error && <p>{error}</p>
}
</Modal.Body>
<Modal.Footer>
{
confirmDiv &&
<>
<Button onClick={handleYes}>Yes</Button>
<Button onClick={props.onHide}>No</Button>
</>
}
{
deleteDiv &&
<>
<Button onClick={props.onHide}>Cancel</Button>
<Button onClick={handleDelete}>Delete</Button>
</>
}
</Modal.Footer>
</Modal>
</div>
);
}
export default TransferDialog;
If I understood well, you can try to replace
<option value={props.items._id} >{props.items.name}</option>
with this
{
props.items.map((element) => <option value={element._id} >{element.name}</option>)
}
You can also try this as it is better
{
renderOptions(props.items)
}
While renderOptions looks like this
function renderOptions(items) => items.map((item) => <option value={item._id} >{item.name}</option>)
Not getting clearly but your finding is to be iterate items on object entities. For that if we condition following aspects could solve the problem.
1 If props.items is array then you only need to use map above the tag
2 If props.items is object then you can use forin loop to iterate and get the named fields and assigned in array state, then use map on the tag.

Resources