Skip to content

Commit f56cc8e

Browse files
Added error handling for checkout page
1 parent cade231 commit f56cc8e

File tree

19 files changed

+239
-137
lines changed

19 files changed

+239
-137
lines changed

client/src/ErrorBoundary.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, {Component} from "react";
2-
import {Grid} from "@material-ui/core";
2+
import {GenericErrorMsg} from "./components/ui/error/GenericErrorMsg";
33

44
class ErrorBoundary extends Component {
55

@@ -26,9 +26,7 @@ class ErrorBoundary extends Component {
2626
render() {
2727
if (this.state.hasError) {
2828
return (
29-
<Grid container justify="center" style={{paddingTop: "2rem", fontSize: "3rem"}}>
30-
<p>Oops! Something went wrong....</p>
31-
</Grid>
29+
<GenericErrorMsg/>
3230
)
3331
}
3432
return this.props.children

client/src/actions/index.js

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import {
88
SAVE_QUERY_STATUS,
99
SHIPPING_ADDRESS_CONFIRMED,
1010
PAYMENT_INFO_CONFIRMED,
11-
PAYMENT_RESPONSE, CART_TOTAL, RESET_SIGN_UP, HANDLE_GOOGLE_AUTH_SIGN_IN, HANDLE_GOOGLE_AUTH_SIGN_OUT,
11+
PAYMENT_RESPONSE,
12+
HANDLE_GOOGLE_AUTH_SIGN_IN,
13+
HANDLE_GOOGLE_AUTH_SIGN_OUT,
14+
PAYMENT_RESPONSE_ERROR,
1215
} from './types';
1316
import {INTERNAL_SERVER_ERROR_CODE, BAD_REQUEST_ERROR_CODE} from '../constants/http_error_codes'
1417
import {SHOPPERS_PRODUCT_INFO_COOKIE, CART_TOTAL_COOKIE, AUTH_DETAILS_COOKIE} from '../constants/cookies'
@@ -191,16 +194,31 @@ export const signUp = formValues => async dispatch => {
191194

192195
export const sendPaymentToken = (token) => async dispatch => {
193196
log.info(`Token = ${JSON.stringify(token)}`)
197+
if(!token || (token && !token.hasOwnProperty("id"))) {
198+
dispatch({
199+
type: PAYMENT_RESPONSE_ERROR,
200+
payload: {errorMsg: "Unable to fetch token. Try again later"}
201+
})
202+
}
203+
204+
let url
205+
if(process.env.REACT_APP_PAYMENT_SERVICE_URL) {
206+
url = `${process.env.REACT_APP_PAYMENT_SERVICE_URL}/payment`
207+
} else {
208+
url = `http://localhost:${process.env.REACT_APP_PAYMENT_SERVICE_PORT}/payment`
209+
}
210+
194211
let config = {
195212
method: 'post',
196-
url: `${process.env.REACT_APP_PAYMENT_SERVICE_URL}/payment`
197-
|| `http://localhost:${process.env.REACT_APP_PAYMENT_SERVICE_PORT}/payment`,
213+
url: url,
198214
headers: {
199215
'Content-Type': 'application/json',
200216
},
201217
data: JSON.stringify(token)
202218
};
203219

220+
log.info(`URL = ${config.url}`)
221+
204222
axios(config)
205223
.then(function (response) {
206224
console.log(JSON.stringify(response.data));
@@ -220,17 +238,16 @@ export const sendPaymentToken = (token) => async dispatch => {
220238

221239
dispatch({
222240
type: PAYMENT_RESPONSE,
223-
payload: paymentResponse
241+
payload: {...paymentResponse, error: false, errorMsg: null}
224242
})
225243

226244
})
227245
.catch(function (error) {
228246
log.error(`[sendPaymentToken]: Error = ${error} `)
229247
dispatch({
230-
type: PAYMENT_RESPONSE,
231-
payload: {error: true}
248+
type: PAYMENT_RESPONSE_ERROR,
249+
payload: {errorMsg: "Something Went Wrong"}
232250
})
233-
return false
234251
});
235252
}
236253

client/src/actions/types.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,32 @@ export const LOAD_HOME_PAGE = "LOAD_HOME_PAGE";
1515
export const LOAD_FILTER_PRODUCTS = "LOAD_FILTER_PRODUCTS";
1616
export const LOAD_FILTER_ATTRIBUTES = "LOAD_FILTER_ATTRIBUTES";
1717
export const LOAD_SHOPPING_BAG_PRODUCTS = "LOAD_SHOPPING_BAG_PRODUCTS";
18+
export const RESET_SHOPPING_BAG_PRODUCTS = "RESET_SHOPPING_BAG_PRODUCTS";
1819
export const LOAD_TABS_DATA = "LOAD_TABS_DATA";
1920

2021
export const REMOVE_FILTER_ATTRIBUTES = "REMOVE_FILTER_ATTRIBUTES";
2122
export const SELECT_SORT_CATEGORY = "SELECT_SORT_CATEGORY";
2223
export const SELECT_PRODUCT_PAGE = "SELECT_PRODUCT_PAGE";
2324
export const SELECT_PRODUCT_DETAIL = "SELECT_PRODUCT_DETAIL";
2425
export const ADD_TO_CART = "ADD_TO_CART";
26+
export const RESET_ADD_TO_CART = "RESET_ADD_TO_CART";
2527
export const CART_TOTAL = "CART_TOTAL";
28+
export const RESET_CART_TOTAL = "RESET_CART_TOTAL";
2629
export const DELIVERY_CHARGES = "DELIVERY_CHARGES";
30+
export const RESET_DELIVERY_CHARGES = "RESET_DELIVERY_CHARGES";
2731

2832
export const SAVE_QUERY_STATUS = "SAVE_QUERY_STATUS";
2933
export const ADD_SELECTED_CATEGORY = "ADD_SELECTED_CATEGORY";
3034
export const REMOVE_SELECTED_CATEGORY = "REMOVE_SELECTED_CATEGORY";
3135
export const SAVE_SORT_LIST = "SAVE_SORT_LIST";
3236
export const SHIPPING_ADDRESS_CONFIRMED = "SHIPPING_ADDRESS_CONFIRMED";
37+
export const RESET_SHIPPING_ADDRESS = "RESET_SHIPPING_ADDRESS";
3338
export const SHIPPING_OPTION_CONFIRMED = "SHIPPING_OPTION_CONFIRMED";
39+
export const RESET_SHIPPING_OPTION = "RESET_SHIPPING_OPTION";
3440
export const PAYMENT_INFO_CONFIRMED = "PAYMENT_INFO_CONFIRMED";
3541
export const PAYMENT_RESPONSE = "PAYMENT_RESPONSE";
42+
export const PAYMENT_RESPONSE_ERROR = "PAYMENT_RESPONSE_ERROR";
43+
export const RESET_PAYMENT_RESPONSE = "RESET_PAYMENT_RESPONSE";
44+
export const RESET_PAYMENT_RESPONSE_ERROR = "RESET_PAYMENT_RESPONSE_ERROR";
45+
3646

client/src/components/routes/checkout/checkout.js

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, {useEffect, useState} from 'react';
22
import log from 'loglevel';
33
import {Paper, Grid, Hidden} from "@material-ui/core";
44
import PriceDetails from "../priceDetails";
@@ -8,13 +8,15 @@ import {makeStyles, withStyles} from '@material-ui/core/styles';
88
import MuiAccordion from '@material-ui/core/Accordion';
99
import MuiAccordionSummary from '@material-ui/core/AccordionSummary';
1010
import MuiAccordionDetails from '@material-ui/core/AccordionDetails';
11-
import {connect, useSelector} from "react-redux";
11+
import {connect, useDispatch, useSelector} from "react-redux";
1212
// import {loadStripe} from "@stripe/stripe-js/pure";
1313
import PaymentButton from "./paymentButton";
1414
import {useAddProductsToShoppingBag} from "../../../hooks/useAddProductsToShoppingBag";
1515
import {getDataViaAPI} from "../../../actions";
1616
import {useCartTotal} from "../../../hooks/useCartTotal";
1717
import {DocumentTitle} from "../../ui/documentTitle";
18+
import {RESET_PAYMENT_RESPONSE_ERROR} from "../../../actions/types";
19+
import BackgroundDisabledSpinner from "../../ui/BackgroundDisabledSpinner";
1820
// import {Elements, ElementsConsumer} from "@stripe/react-stripe-js";
1921
// import Payment from "./payment"
2022

@@ -80,7 +82,33 @@ const shippingOptionPanel = 'shipOptPanel'
8082
function Checkout(props) {
8183
const shippingAddress = useSelector(state => state.shippingAddressReducer)
8284
const shippingOption = useSelector(state => state.shippingOptionReducer)
85+
const {timestamp} = useSelector(state => state.paymentResponseReducer)
8386
const classes = useGridStyles();
87+
const dispatch = useDispatch()
88+
const [isLoading, setIsLoading] = useState(false);
89+
90+
const setIsLoadingState = () => {
91+
setIsLoading(true);
92+
}
93+
94+
useEffect(() => {
95+
log.info(`[Checkout]: Component did mount...`)
96+
setIsLoading(false)
97+
98+
// eslint-disable-next-line
99+
}, [timestamp])
100+
101+
useEffect(() => {
102+
103+
return () => {
104+
log.info(`[Checkout] Component will unmount...`)
105+
dispatch({
106+
type: RESET_PAYMENT_RESPONSE_ERROR
107+
})
108+
}
109+
110+
// eslint-disable-next-line
111+
}, [])
84112

85113
useCartTotal()
86114
useAddProductsToShoppingBag(props.getDataViaAPI)
@@ -97,10 +125,11 @@ function Checkout(props) {
97125
)
98126
}
99127

100-
log.info("[Checkout] Rendering Checkout Component.")
128+
log.info(`[Checkout] Rendering Checkout Component. isLoading = ${isLoading}`)
101129

102130
return (
103131
<Grid container justify={"center"} classes={{root: classes.root}}>
132+
{isLoading ? <BackgroundDisabledSpinner/> : null}
104133

105134
<Grid item xs={12} sm={11} md={5}>
106135

@@ -152,6 +181,7 @@ function Checkout(props) {
152181
<Grid item sm={11} md={4} style={{height: 300, marginTop: "1rem"}}>
153182
<Paper square style={{width: "inherit"}}>
154183
<PriceDetails buttonName="PLACE ORDER"/>
184+
<PaymentButton disabled={!shippingOption.submitted} loadingHandler={setIsLoadingState}/>
155185
</Paper>
156186
</Grid>
157187
</Hidden>
@@ -161,7 +191,7 @@ function Checkout(props) {
161191
style={{height: "fit-content", marginTop: "1rem", position: "sticky", top: 80}}>
162192
<Paper square style={{width: "inherit"}}>
163193
<PriceDetails buttonName="PLACE ORDER"/>
164-
<PaymentButton disabled={!shippingOption.submitted}/>
194+
<PaymentButton disabled={!shippingOption.submitted} loadingHandler={setIsLoadingState}/>
165195
</Paper>
166196
</Grid>
167197
</Hidden>

client/src/components/routes/checkout/continueButton.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function ContinueButton(props) {
2626

2727
const renderContinueMobileBtn = () => {
2828
return (
29-
<Grid item container justify="center" style={{paddingTop: 30, margin: 0}}>
29+
<Grid item container justify="center" style={{padding: "30px 0", margin: 0}}>
3030
<Button variant="contained" size="large" style={{
3131
...continueButtonStyle, width: "85%"
3232
}} type={props.type} disabled={props.action} onClick={props.buttonHandler}>

client/src/components/routes/checkout/paymentButton.js

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,46 +4,29 @@ import {Button, Grid} from "@material-ui/core";
44
import {connect} from "react-redux";
55
import {sendPaymentToken} from "../../../actions"
66
import log from 'loglevel';
7+
import AlertModal from "../../ui/alertModal";
78

89
class PaymentButton extends Component {
910

1011
_GrandTotal = 0
1112

12-
constructor(props) {
13-
super(props);
14-
this.state = {
15-
paymentBtnClicked: false
16-
}
17-
}
18-
19-
componentDidMount() {
20-
log.info(`[PaymentButton] Component Did Mount...paymentResponse = ${JSON.stringify(this.props.paymentResponse)}`)
21-
if(this.props.paymentResponse && this.props.paymentResponse.hasOwnProperty("error")) {
22-
this.setState({paymentBtnClicked: true})
23-
}
24-
}
25-
2613
getGrandTotal = () => {
2714
this._GrandTotal = (this.props.cartTotal + this.props.deliveryCharges) * 100
2815
return this._GrandTotal
2916
}
3017

3118
onToken = (token) => {
19+
log.info("[PaymentButton] onToken setting loadingHandler to true")
20+
this.props.loadingHandler(true)
3221

33-
this.setState({paymentBtnClicked: true})
34-
35-
let value = this.props.sendPaymentToken({
22+
this.props.sendPaymentToken({
3623
...token,
3724
amount: this._GrandTotal,
3825
currency: "USD",
3926
address: this.props.shippingAddressForm.values,
4027
addToCart: this.props.addToCart,
4128
shippingOption: this.props.shippingOption
4229
})
43-
44-
if(value) {
45-
this.setState({paymentBtnClicked: false})
46-
}
4730
}
4831

4932
renderButton = () => {
@@ -52,7 +35,7 @@ class PaymentButton extends Component {
5235
<Grid container justify="center" style={{padding: "2rem 0 2rem 0"}}>
5336
<Grid item lg={9}>
5437
<Button variant="contained" size="medium"
55-
disabled={this.state.paymentBtnClicked || this.props.disabled}
38+
disabled={this.props.disabled}
5639
style={{
5740
width: '100%', height: 50, color: 'white',
5841
fontWeight: "bold", backgroundColor: "#e01a2b",
@@ -66,11 +49,17 @@ class PaymentButton extends Component {
6649
}
6750

6851
render() {
69-
console.log(`[PaymentButton] Rendering PaymentButton Component...`)
52+
log.info(`[PaymentButton] Rendering PaymentButton Component...error = ${this.props.paymentResponse.error}`)
7053

7154
return (
7255
<>
73-
{this.state.paymentBtnClicked || this.props.disabled ?
56+
<AlertModal title="Payment Error"
57+
question="Something went wrong. Please try again later."
58+
enable={this.props.paymentResponse.error}
59+
timestamp={this.props.paymentResponse.timestamp}
60+
/>
61+
62+
{this.props.disabled ?
7463
this.renderButton():
7564
<StripeCheckout
7665
token={this.onToken}
@@ -97,10 +86,4 @@ const mapStateToProps = (state) => {
9786
})
9887
}
9988

100-
function paymentButtonPropsAreEqual(prevProps, nextProps) {
101-
return prevProps.disabled === nextProps.disabled;
102-
}
103-
104-
const wrapperMemo = React.memo(PaymentButton, paymentButtonPropsAreEqual);
105-
106-
export default connect(mapStateToProps, {sendPaymentToken})(wrapperMemo)
89+
export default connect(mapStateToProps, {sendPaymentToken})(PaymentButton)

client/src/components/routes/checkout/shippingAddress.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class ShippingAddressForm extends Component {
9999
const renderShippingForm = () => {
100100
return (
101101
<Grid item style={{width: "100%", height: "fit-content"}}>
102-
<Grid item xs={12} sm={12}>
102+
<Grid item xs={12}>
103103
<form onSubmit={this.handleSubmit} className={classes.root}
104104
style={{width: "inherit"}}>
105105

client/src/components/routes/signup/signUp.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import log from "loglevel";
55
import {useDispatch, useSelector} from "react-redux";
66
import {Dimmer, Loader} from "semantic-ui-react";
77
import {DocumentTitle} from "../../ui/documentTitle";
8-
import {RESET_SIGN_IN_ERROR, RESET_SIGN_UP} from "../../../actions/types";
8+
import {RESET_SIGN_UP} from "../../../actions/types";
99

1010
const SignUp = () => {
1111
const [isLoading, setIsLoading] = useState(false);

0 commit comments

Comments
 (0)