Skip to content

Commit b453632

Browse files
author
WebDeveloperGuide
committed
Some structure and code revise.
COD and Card Payment mehod added Complete Order submit functionality added
1 parent 01deb86 commit b453632

File tree

21 files changed

+325
-92
lines changed

21 files changed

+325
-92
lines changed

web_panel/src/components/CartProduct.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import {useDispatch} from 'react-redux';
33
import {removeFromCart, increaseProductQty, decreaseProductQty} from '../redux/actions/cartActions';
44

5-
const CartProduct = ({detail}) => {
5+
const CartProduct = ({detail}) => {
66
const {id,image, name, price, qty} = detail;
77
const dispatch = useDispatch();
88
const removeItemFromCart = (id) =>{

web_panel/src/components/CartTotal.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@ import {Link} from 'react-router-dom';
44

55
const CartTotal = () => {
66
const cart = useSelector((state) => state.cart);
7-
const { cartItems } = cart;
7+
const { cartItems } = cart;
88
const cartTotal = cartItems.reduce((a, i) => a + i.qty * i.price, 0).toFixed(2);
99
return(
1010
<>
1111
<footer>
1212
<h3 className="cart-total text-slanted">total : ${cartTotal}</h3>
13-
<Link to="/shipping"><button className="cart-checkout btn">checkout</button></Link>
13+
{
14+
cartItems.length > 0 ?
15+
<Link to="/shipping"><button className="cart-checkout btn">checkout</button></Link>
16+
:
17+
""
18+
}
1419
</footer>
1520
</>
1621
)

web_panel/src/components/FeaturedProducts.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const FeaturedProducts = () => {
1111
const featuredProduct = products.slice(0, 6);
1212
const renderList = featuredProduct.map((product)=>{
1313
return(
14-
<Product detail={product} key={product.id}/>
14+
<Product detail={product} key={product._id}/>
1515
)
1616
})
1717

web_panel/src/components/PaymentForm.js

Lines changed: 82 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,25 @@ import PageHeading from '../components/PageHeading';
55
import ProductDetail from '../components/ProductDetail';
66
import Sidebar from '../components/Sidebar';
77
import Cart from '../components/Cart';
8-
import {Link} from 'react-router-dom';
8+
import {Link, useHistory} from 'react-router-dom';
99
import {showCart} from '../redux/actions/cartActions';
1010
import { CardElement, useStripe, useElements } from "@stripe/react-stripe-js";
11+
import { createOrder, processPayment } from '../redux/actions/orderActions';
1112
import axios from 'axios';
1213

1314

14-
const PaymentForm = ({history}) => {
15+
const PaymentForm = () => {
1516

16-
const [submitted, setSubmitted] = useState(false);
17+
const history = useHistory()
18+
19+
20+
const [submitted, setSubmitted] = useState(false);
21+
const [btnDisable, setBtnDisable] = useState(false);
22+
const [paymentMethod, setPaymentMethod] = useState('Cash on Delivery');
1723
const [showCardPayment, setShowCardPayment] = useState(false);
24+
const userInfo = useSelector((state) => state.userPanelLogin.userInfo.data);
25+
const user = userInfo[0]._id;
26+
1827
const stripe = useStripe();
1928
const elements = useElements();
2029
const dispatch = useDispatch();
@@ -37,7 +46,30 @@ const PaymentForm = ({history}) => {
3746

3847
const shippingAddress = useSelector((state) => state.cart.shippingAddress);
3948
const { street1, street2, city, state, zip, country } = shippingAddress;
40-
49+
50+
const cartItems = useSelector((state)=> state.cart.cartItems);
51+
const orderItems = [];
52+
const cartItemsList = cartItems.map((product)=>{
53+
const {name,qty,image,price, id} = product;
54+
orderItems.push({
55+
name,
56+
qty,
57+
image,
58+
price,
59+
product: id,
60+
})
61+
});
62+
63+
const itemsPrice = orderItems.reduce((a, i) => a + i.qty * i.price, 0).toFixed(2);
64+
const shippingPrice = itemsPrice > 100 ? 0 : 10;
65+
const taxPrice = (0.15 * itemsPrice).toFixed(2);
66+
const totalPrice = ((parseFloat(itemsPrice) + parseFloat(shippingPrice) + parseFloat(taxPrice)) * 100).toFixed();
67+
68+
//Redirect to shipping page if address is not filled
69+
if (cartItems.length === 0) {
70+
history.push("/");
71+
}
72+
4173
//Redirect to shipping page if address is not filled
4274
if (Object.keys(shippingAddress).length === 0) {
4375
history.push("/shipping");
@@ -66,45 +98,45 @@ const PaymentForm = ({history}) => {
6698
const handleSubmit = async (e) => {
6799
e.preventDefault();
68100
setSubmitted(true);
69-
if (!stripe || !elements) {
70-
// Stripe.js has not loaded yet. Make sure to disable
71-
// form submission until Stripe.js has loaded.
72-
return;
101+
setBtnDisable(true);
102+
103+
if(showCardPayment){
104+
105+
if (!stripe || !elements) {
106+
// Stripe.js has not loaded yet. Make sure to disable
107+
// form submission until Stripe.js has loaded.
108+
return;
109+
}
110+
// Get a reference to a mounted CardElement. Elements knows how
111+
// to find your CardElement because there can only ever be one of
112+
// each type of element.
113+
114+
// use stripe.createToken to get a unique token for the card
115+
const { error, token } = await stripe.createToken(elements.getElement(CardElement));
116+
117+
if (!error) {
118+
dispatch(processPayment({token: token.id, orderItems, shippingAddress, paymentMethod, user, itemsPrice, shippingPrice, taxPrice, totalPrice, price: totalPrice, isPaid:true}));
119+
} else {
120+
setSubmitted(false);
121+
setBtnDisable(false);
122+
}
123+
124+
125+
}else{
126+
if(orderItems && shippingAddress && paymentMethod ){
127+
dispatch(createOrder({orderItems, shippingAddress, paymentMethod, user, itemsPrice, shippingPrice, taxPrice, totalPrice}));
128+
history.push('/');
129+
}
73130
}
74-
// Get a reference to a mounted CardElement. Elements knows how
75-
// to find your CardElement because there can only ever be one of
76-
// each type of element.
77-
78-
79-
// use stripe.createToken to get a unique token for the card
80-
const { error, token } = await stripe.createToken(cardElement);
81-
82-
if (!error) {
83-
// Backend is not implemented yet, but once there isn’t any errors,
84-
// you can pass the token and payment data to the backend to complete
85-
// the charge
86-
axios
87-
.post("checkout/payment", {
88-
token: token.id,
89-
currency: "EGP",
90-
price: 1000, // or 10 pounds (10*100). Stripe charges with the smallest price unit allowed
91-
})
92-
.then((resp) => {
93-
alert("Your payment was successful");
94-
})
95-
.catch((err) => {
96-
console.log(err);
97-
});
98-
} else {
99-
console.log(error);
100-
}
101131
}
102132

103133
const changePaymentMethod = (e) =>{
104134
if(e.target.value === 'card'){
105135
setShowCardPayment(true);
136+
setPaymentMethod('Card')
106137
}else{
107138
setShowCardPayment(false);
139+
setPaymentMethod('Cash on Delivery')
108140
}
109141
}
110142

@@ -116,6 +148,12 @@ const PaymentForm = ({history}) => {
116148
} else {
117149
displayError.textContent = '';
118150
}
151+
152+
if(event.complete){
153+
setBtnDisable(false);
154+
}else{
155+
setBtnDisable(true);
156+
}
119157
}
120158

121159
useEffect(() => {
@@ -164,7 +202,15 @@ const PaymentForm = ({history}) => {
164202
}
165203

166204
<div className="d-flex justify-content-center mt-3 login_container">
167-
<button className="btn login_btn">Proceed</button>
205+
<button className="btn login_btn" disabled={btnDisable} >
206+
207+
{submitted ? (
208+
<i className="fas fa-spinner fa-spin"></i>
209+
): (
210+
"Place Order"
211+
)
212+
}
213+
</button>
168214
</div>
169215
</form>
170216
</div>

web_panel/src/components/Product.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {addToCart} from '../redux/actions/cartActions';
55

66
const Products = (props) => {
77

8-
const {id,thumbnail,price,title} = props.detail;
8+
const {_id,image,price,title} = props.detail;
99
const dispatch = useDispatch();
1010

1111
const addToCartHandle = (product) => {
@@ -16,12 +16,12 @@ const Products = (props) => {
1616
<>
1717
<article className="product">
1818
<div className="product-container">
19-
<img src={thumbnail} className="product-img img" alt={title} />
19+
<img src={image} className="product-img img" alt={title} />
2020
<div className="product-icons">
21-
<Link to={`/product/${id}`} className="product-icon" title="View">
21+
<Link to={`/product/${_id}`} className="product-icon" title="View">
2222
<i className="fas fa-search" />
2323
</Link>
24-
<button className="product-cart-btn product-icon" title="Add to Cart" data-id={id} onClick={()=>addToCartHandle(props.detail)}>
24+
<button className="product-cart-btn product-icon" title="Add to Cart" data-id={_id} onClick={()=>addToCartHandle(props.detail)}>
2525
<i className="fas fa-shopping-cart" />
2626
</button>
2727
</div>

web_panel/src/components/ProductDetail.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import {useDispatch} from 'react-redux';
33
import {addToCart} from '../redux/actions/cartActions';
44

55
const Products = (props) => {
6-
const {id,thumbnail,title,price,description} = props.details;
6+
const productDetails = props.details.data;
7+
const {image,title,price,description} = productDetails;
78
const [itemQty, setItemQty] = useState(1);
89
const dispatch = useDispatch();
910
const addToCartHandle = (product) => {
@@ -17,7 +18,7 @@ const Products = (props) => {
1718
<>
1819
<section className="single-product section">
1920
<div className="section-center single-product-center">
20-
<img src={thumbnail} className="single-product-img img" alt="" />
21+
<img src={image} className="single-product-img img" alt="" />
2122
<article className="single-product-info">
2223
<div>
2324
<h2 className="single-product-title">{title}</h2>
@@ -44,7 +45,7 @@ const Products = (props) => {
4445
<option value="10">10</option>
4546
</select>
4647
</p>
47-
<button className="addToCartBtn btn" data-id="id" onClick={() => addToCartHandle(props.details)}>add to cart</button>
48+
<button className="addToCartBtn btn" data-id="id" onClick={() => addToCartHandle(productDetails)}>add to cart</button>
4849
</div>
4950
</article>
5051
</div>

web_panel/src/components/Products.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@ import Loading from '../components/Loading';
88
const Products = () => {
99

1010
const products = useSelector((state)=> state.allProducts.products);
11-
1211
const renderList = products.map((product)=>{
1312
return(
14-
<Product detail={product} key={product.id}/>
13+
<Product detail={product} key={product._id}/>
1514
)
1615
})
1716

web_panel/src/index.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ Featured Products
519519
}
520520
.product .img {
521521
height: 13rem;
522+
object-fit: contain;
522523
}
523524
}
524525
/*
@@ -668,6 +669,7 @@ Products Page
668669
}
669670
.products-container .product-img {
670671
height: 10rem;
672+
object-fit:contain;
671673
}
672674
.products-container .product-name {
673675
font-size: 0.85rem;

web_panel/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ axios.defaults.headers.post['Content-Type'] = 'application/json';
1313
if(typeof userInfo !== 'undefined' && userInfo !== null){
1414
const token = userInfo.token;
1515
if(typeof token != undefined && token){
16-
axios.defaults.headers.common['Authorization'] = `Bearer ${userInfo.token}`;//send token
16+
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;//send token
1717
}
1818
}
1919

web_panel/src/pages/Shipping.js

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ const ShippingPage = ({history}) => {
1616
const shippingAddress = useSelector((state) => state.cart.shippingAddress);
1717
const { street1, street2, city, state, zip, country } = shippingAddress;
1818

19+
const cartItems = useSelector((state)=> state.cart.cartItems);
20+
21+
//Redirect to home page if no items in cart
22+
if (Object.keys(cartItems).length === 0) {
23+
history.push("/");
24+
}
25+
1926
const [formState,setFormState] = useState({
2027
values:shippingAddress
2128
});
@@ -37,9 +44,9 @@ const ShippingPage = ({history}) => {
3744
const handleSubmit = (e) => {
3845
e.preventDefault();
3946
setSubmitted(true);
40-
const { street1,street2, city, state, zip, country } = formState.values;
47+
const { customer_name, street1,street2, city, state, zip, country } = formState.values;
4148

42-
if (street1 && city && state && zip && country) {
49+
if (customer_name && street1 && city && state && zip && country) {
4350
dispatch(saveShippingAddress(formState.values));
4451
history.push("/payment");
4552
}
@@ -60,7 +67,18 @@ const ShippingPage = ({history}) => {
6067
<h4 className="content-heading">Delivery Address</h4>
6168
<div className="d-flex justify-content-center form_container auth-page-container shipping-page-container">
6269
<form onSubmit={handleSubmit} autoComplete="off">
63-
<div className="input-group">
70+
<div className="input-group">
71+
<input type="text" className={'form-control form-control-lg' + (submitted && !formState.values.customer_name ? ' is-invalid' : '')}
72+
name="customer_name"
73+
placeholder="Customer Name"
74+
onChange={handleChange}
75+
value={formState.values.customer_name || ''}
76+
/>
77+
</div>
78+
{submitted && !formState.values.customer_name &&
79+
<div className="inline-errormsg">Name is required</div>
80+
}
81+
<div className="input-group mt-3">
6482
<input type="text" className={'form-control form-control-lg' + (submitted && !formState.values.street1 ? ' is-invalid' : '')}
6583
name="street1"
6684
placeholder="Street 1"
@@ -130,7 +148,14 @@ const ShippingPage = ({history}) => {
130148
<div className="inline-errormsg">Country is required</div>
131149
}
132150
<div className="d-flex justify-content-center mt-3 login_container">
133-
<button className="btn login_btn">Continue</button>
151+
<button className="btn login_btn">
152+
{submitted ? (
153+
<i className="fas fa-spinner fa-spin"></i>
154+
): (
155+
"Continue"
156+
)
157+
}
158+
</button>
134159
</div>
135160
</form>
136161
</div>

0 commit comments

Comments
 (0)