//this is Cartscreen.jsx file
import React, { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Link } from 'react-router-dom'
//useDispatch for request and useSelector for data retrive
import { Row, Col, Form, Button, Card, Image, ListGroup, ListGroupItem } from 'react-bootstrap'
import { addToCart, removeFromCart } from '../actions/cartAction'
import { useNavigate, useParams, useLocation } from 'react-router-dom'
import Message from '../components/shared/Message'
const CartScreen = () => {
const params = useParams()
const location = useLocation()
const navigate = useNavigate()
const productId = params.id
const qty = location.search ? Number(location.search.split('=')[1]) : 1
const dispatch = useDispatch()
useEffect(() => {
//checking product is coming or not
if (productId) {
dispatch(addToCart(productId, qty))//both value will remain in redux
}
}, [dispatch, productId, qty])//these passed as dependencies as array
const cart = useSelector(state => state.cart)
const { cartItems } = cart;
const removeFromCartHandler = (id) => {
dispatch(removeFromCart(id))
}
const checkOut = () => {
//navigate("/login", { state: { redirect: "shipping" } });
navigate("/login?redirect=shipping");
}
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) => (
<ListGroupItem 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>
<Button
type="button"
variant="light"
onClick={() => removeFromCartHandler(item.product)}
>
<i
className="fa fa-trash text-danger"
aria-hidden="true"
></i>
</Button>
</Col>
</Row>
</ListGroupItem>
))}
</ListGroup>
)}
</Col>
<Col md={4}>
<Card>
<ListGroup variant="flush">
<ListGroupItem>
<h2>
subtotal ({cartItems.reduce((acc, item) => acc + item.qty, 0)}
) items
</h2>
$
{cartItems
.reduce((acc, item) => acc + item.qty * item.price, 0)
.toFixed(2)}
</ListGroupItem>
<Button
type="button"
className="btn-block"
disabled={cartItems.length === 0}
onClick={checkOut}
>
Proceed to checkOut
</Button>
</ListGroup>
</Card>
</Col>
</Row>
</>
)
}
export default CartScreen
//this is ShippingScreen.jsx file
import React, { useState } from 'react';
import { Form, useNavigate } from 'react-router-dom';
import { Button } from 'react-bootstrap';
import { useSelector, useDispatch } from 'react-redux';
import { saveShippingAddress } from '../actions/cartAction';
import FormContainer from './../components/shared/FormContainer';
const ShippingScreen = () => {
const navigate = useNavigate()
const dispatch = useDispatch()
const cart = useSelector(state => state.cart)
const { shippingAddress } = cart
const [address, setAddress] = useState(shippingAddress?.address || '')
const [city, setCity] = useState(shippingAddress?.city || '')
const [postal, setPostal] = useState(shippingAddress?.postal || '')
const [country, setCountry] = useState(shippingAddress?.country || '')
const submitHandler = (e) => {
e.preventDefault()
//dispatch
dispatch(saveShippingAddress({ address, city, postal, country }))
navigate('/payment')
}
return (
<div>
<FormContainer>
<Form onSubmit={submitHandler}>
<Form.Group controlId='address'>
<Form.Label>Address</Form.Label>
<Form.Control type='text'
placeholder='Enter Address'
value={address}
onChange={e => setAddress(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='city'>
<Form.Control type='text'
placeholder='City'
value={city}
onChange={e => setCity(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='postal'>
<Form.Control type='text'
placeholder='Postal Code'
value={postal}
onChange={e => setPostal(e.target.value)}>
</Form.Control>
</Form.Group>
<Form.Group controlId='country'>
<Form.Control type='text'
placeholder='Country'
value={country}
onChange={e => setCountry(e.target.value)}>
</Form.Control>
</Form.Group>
<Button type='submit' variant='primary'>Continue</Button>
</Form>
</FormContainer>
</div>
)
}
export default ShippingScreen
below cartAction.js file
import axios from 'axios'
import {
CART_ADD_ITEM,
CART_REMOVE_ITEM,
CART_SAVE_SHIPPING_ADDRESS} from '../constants/CartConstant'
export const addToCart =(id,qty)=>async(dispatch,getstate)=>{
const {data} = await axios.get(`/api/products/${id}`)
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))
};
//we use getstate because we have items in local storage
export const removeFromCart = (id)=>(dispatch,getState) =>{
dispatch({
type:CART_REMOVE_ITEM,
payload:id
})
localStorage.setItem('cartItems',JSON.stringify(getState().cart.cartItems))
};
export const saveShippingAddress = (data)=>(dispatch)=>{
dispatch({type:CART_SAVE_SHIPPING_ADDRESS,payload:data,});
localStorage.setItem('shippingAddress',JSON.stringify(data))
};
i am trying to go to shipping.jsx file but after clicking on checkout button which present in cartScreen.jsx file it redirect me to home page '/'
Things i have tried
\> try different way to adjust the link which send to shipping page
\>different way to use hooks
\>checked if routes are correct or not but incase if u ask
<Route path="/shipping" element={<ShippingScreen/>}></Route>