Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
E
ecommerce-maven
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ascend
ecommerce-maven
Commits
5820e68d
Commit
5820e68d
authored
May 14, 2021
by
Kyle Muldoon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added promotions info to Cart / OrderPage. Also added loading animation when sending an order
parent
ee17f19c
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
190 additions
and
60 deletions
+190
-60
cart_processing_actions.js
ecom-web/src/actions/cart_processing_actions.js
+13
-1
header.css
ecom-web/src/components/Header/header.css
+1
-1
ReviewOrder.js
ecom-web/src/components/checkout/ReviewOrder.js
+71
-48
checkout.css
ecom-web/src/components/checkout/checkout.css
+52
-2
checkout.js
ecom-web/src/components/checkout/checkout.js
+10
-3
CartItem.js
ecom-web/src/components/shopping-cart/CartItem.js
+11
-1
shopping-cart.css
ecom-web/src/components/shopping-cart/shopping-cart.css
+3
-0
shopping-cart.js
ecom-web/src/components/shopping-cart/shopping-cart.js
+3
-2
cart_processing_reducer.js
ecom-web/src/reducers/cart_processing_reducer.js
+7
-2
cart_processing_util.js
ecom-web/src/util/cart_processing_util.js
+19
-0
No files found.
ecom-web/src/actions/cart_processing_actions.js
View file @
5820e68d
import
{
priceCalcUtil
,
numItemsCalcUtil
}
from
'../util/cart_processing_util'
import
{
priceCalcUtil
,
numItemsCalcUtil
,
promoCalcUtil
}
from
'../util/cart_processing_util'
export
const
GET_TOTAL_PRICE
=
"GET_TOTAL_PRICE"
export
const
GET_NUM_ITEMS
=
"GET_NUM_ITEMS"
export
const
GET_CART_PRODUCTS
=
"GET_CART_PRODUCTS"
export
const
GET_TOTAL_PROMOTIONS
=
"GET_TOTAL_PROMOTIONS"
export
const
getTotalPrice
=
(
totalPrice
)
=>
({
type
:
GET_TOTAL_PRICE
,
...
...
@@ -19,6 +20,11 @@ export const getCartProducts = (cartProducts) => ({
payload
:
cartProducts
})
export
const
getTotalPromotions
=
(
totalPromotions
)
=>
({
type
:
GET_TOTAL_PROMOTIONS
,
payload
:
totalPromotions
})
export
const
calcTotalPrice
=
(
productList
)
=>
{
return
(
dispatch
)
=>
{
...
...
@@ -26,6 +32,12 @@ export const calcTotalPrice = (productList) => {
}
}
export
const
calcTotalPromotions
=
(
productList
)
=>
{
return
(
dispatch
)
=>
{
return
dispatch
(
getTotalPromotions
(
promoCalcUtil
(
productList
)))
}
}
export
const
calcNumItems
=
(
productList
)
=>
{
return
(
dispatch
)
=>
{
return
dispatch
(
getNumItems
(
numItemsCalcUtil
(
productList
)))
...
...
ecom-web/src/components/Header/header.css
View file @
5820e68d
...
...
@@ -121,4 +121,4 @@
.company-banner
{
height
:
50
;
width
:
100px
;
}
\ No newline at end of file
}
ecom-web/src/components/checkout/ReviewOrder.js
View file @
5820e68d
...
...
@@ -22,58 +22,81 @@ export default function ReviewOrder(props) {
<
p
>
Step
3
-
Order
Summary
<
/p
>
<
/div
>
<
div
id
=
"orderSummaryContainer"
>
<
div
className
=
"OrderSummaryElement"
id
=
"itemsPrice"
>
<
div
>
Items
({
props
.
numCartItems
}):
<
/div
>
<
div
>
$
{
parseFloat
(
props
.
itemsTotal
).
toFixed
(
2
)}
{
props
.
loading
===
0
?
<
div
id
=
"orderSummaryContainer"
>
<
div
className
=
"OrderSummaryElement"
id
=
"itemsPrice"
>
<
div
>
Items
({
props
.
numCartItems
}):
<
/div
>
<
div
>
$
{
parseFloat
(
props
.
itemsTotal
).
toFixed
(
2
)}
<
/div
>
<
/div
>
<
div
className
=
"OrderSummaryElement"
id
=
"promotionsApplied"
>
<
div
>
Promotions
Discount
:
<
/div
>
<
div
>
<
span
style
=
{{
color
:
'green'
,
fontWeight
:
'bold'
}}
>
-
$
{
parseFloat
(
props
.
promotionsDiscount
).
toFixed
(
2
)}
<
/span
>
<
/div
>
<
/div
>
<
div
className
=
"OrderSummaryElement"
id
=
"shippingHandling"
>
<
div
id
=
"shippingHandlingLabel"
>
Shipping
and
Handling
:
<
/div
>
<
div
id
=
"shippingHandlingPrice"
>
{
/* ${parseFloat(props.shippingHandling).toFixed(2)} */
}
<
span
style
=
{{
color
:
'green'
,
fontWeight
:
'bold'
}}
>
FREE
<
/span
>
<
/div
>
<
/div
>
<
div
className
=
"OrderSummaryElement"
id
=
"beforeTax"
>
<
div
id
=
"beforeTaxLabel"
>
Total
Before
Tax
<
/div
>
<
div
id
=
"beforeTaxPrice"
>
$
{
calcTotalBeforeTax
(
props
.
itemsTotal
-
props
.
promotionsDiscount
,
props
.
shippingHandling
).
toFixed
(
2
)}
<
/div
>
<
/div
>
<
div
className
=
"OrderSummaryElement"
id
=
"taxCalculated"
>
<
div
id
=
"taxCalculatedLabel"
>
Estimated
Tax
:
<
/div
>
<
div
id
=
"taxCalculatedPrice"
>
$
{
calcTaxAmount
(
props
.
itemsTotal
-
props
.
promotionsDiscount
,
props
.
shippingHandling
,
props
.
taxRate
).
toFixed
(
2
)}
<
/div
>
<
/div
>
<
div
className
=
"OrderSummaryElement"
id
=
"orderTotal"
>
<
div
id
=
"orderTotalLabel"
>
Order
Total
:
<
/div
>
<
div
id
=
"orderTotalPrice"
>
$
{
calcGrandTotal
(
props
.
itemsTotal
-
props
.
promotionsDiscount
,
props
.
shippingHandling
,
props
.
taxRate
).
toFixed
(
2
)}
<
/div
>
<
/div
>
<
/div
>
<
/div
>
:
<
div
className
=
"OrderSummaryElement"
id
=
"shippingHandling"
>
<
div
id
=
"shippingHandlingLabel"
>
Shipping
and
Handling
:
<
div
id
=
"loadingElement"
>
<
div
class
=
"lds-ring"
><
div
><
/div><div></
div
><
div
><
/div><div></
div
><
/div
>
<
/div
>
<
div
id
=
"shippingHandlingPrice"
>
$
{
parseFloat
(
props
.
shippingHandling
).
toFixed
(
2
)}
<
/div
>
<
/div
>
<
div
className
=
"OrderSummaryElement"
id
=
"beforeTax"
>
<
div
id
=
"beforeTaxLabel"
>
Total
Before
Tax
<
/div
>
<
div
id
=
"beforeTaxPrice"
>
$
{
calcTotalBeforeTax
(
props
.
itemsTotal
,
props
.
shippingHandling
).
toFixed
(
2
)}
<
/div
>
<
/div
>
<
div
className
=
"OrderSummaryElement"
id
=
"taxCalculated"
>
<
div
id
=
"taxCalculatedLabel"
>
Estimated
Tax
:
<
/div
>
<
div
id
=
"taxCalculatedPrice"
>
$
{
calcTaxAmount
(
props
.
itemsTotal
,
props
.
shippingHandling
,
props
.
taxRate
).
toFixed
(
2
)}
<
/div
>
<
/div
>
<
div
className
=
"OrderSummaryElement"
id
=
"orderTotal"
>
<
div
id
=
"orderTotalLabel"
>
Order
Total
:
<
/div
>
<
div
id
=
"orderTotalPrice"
>
$
{
calcGrandTotal
(
props
.
itemsTotal
,
props
.
shippingHandling
,
props
.
taxRate
).
toFixed
(
2
)}
<
/div
>
<
/div
>
<
/div
>
}
<
/div
>
)
...
...
ecom-web/src/components/checkout/checkout.css
View file @
5820e68d
...
...
@@ -9,6 +9,7 @@
flex-direction
:
column
;
justify-content
:
flex-start
;
align-items
:
center
;
padding-top
:
40px
;
}
.OrderDirectionsElement
{
...
...
@@ -47,8 +48,9 @@
flex-direction
:
row
;
width
:
40%
;
justify-content
:
space-between
;
margin-bottom
:
1
0
px
;
margin-bottom
:
1
5
px
;
font-size
:
150%
;
}
#orderTotal
{
...
...
@@ -79,4 +81,52 @@
color
:
red
;
font-weight
:
bold
;
font-size
:
120%
;
}
\ No newline at end of file
}
/* ////// */
.lds-ring
{
display
:
inline-block
;
position
:
relative
;
width
:
150px
;
height
:
150px
;
}
.lds-ring
div
{
box-sizing
:
border-box
;
display
:
block
;
position
:
absolute
;
width
:
150px
;
height
:
150px
;
margin
:
8px
;
border
:
8px
solid
#000
;
border-radius
:
50%
;
animation
:
lds-ring
1.2s
cubic-bezier
(
0.5
,
0
,
0.5
,
1
)
infinite
;
border-color
:
rgb
(
0
,
77
,
112
)
transparent
transparent
transparent
;
}
.lds-ring
div
:nth-child
(
1
)
{
animation-delay
:
-0.45s
;
}
.lds-ring
div
:nth-child
(
2
)
{
animation-delay
:
-0.3s
;
}
.lds-ring
div
:nth-child
(
3
)
{
animation-delay
:
-0.15s
;
}
@keyframes
lds-ring
{
0
%
{
transform
:
rotate
(
0deg
);
}
100
%
{
transform
:
rotate
(
360deg
);
}
}
#loadingElement
{
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
}
ecom-web/src/components/checkout/checkout.js
View file @
5820e68d
...
...
@@ -9,7 +9,7 @@ import './checkout.css'
import
{
dispatchOrderInfo
}
from
'./../../actions/checkout_actions'
import
{
Redirect
}
from
'react-router'
import
{
updateUserCart
}
from
'./../../actions/cart_actions'
import
{
calcTotalPrice
,
calcNumItems
,
storeCartItemsInProcessing
}
from
'./../../actions/cart_processing_actions'
import
{
calcTotalPrice
,
calcNumItems
,
storeCartItemsInProcessing
,
calcTotalPromotions
}
from
'./../../actions/cart_processing_actions'
export
default
function
Checkout
()
{
const
dispatch
=
useDispatch
()
///////////////////////
...
...
@@ -41,8 +41,9 @@ export default function Checkout() {
///////////////////////
const
numCartItems
=
useSelector
(
state
=>
state
.
cartProcessing
.
numItems
)
const
itemsTotal
=
useSelector
(
state
=>
state
.
cartProcessing
.
totalPrice
)
const
taxRate
=
0.0725
const
shippingHandling
=
9.00
const
promotionsDiscount
=
useSelector
(
state
=>
state
.
cartProcessing
.
totalPromotions
)
const
taxRate
=
0.0
const
shippingHandling
=
0.00
///////////////////////
// Submit Button State
///////////////////////
...
...
@@ -54,6 +55,7 @@ export default function Checkout() {
///////////////////////
const
user
=
useSelector
(
state
=>
state
.
user
.
currentUser
)
const
cart
=
useSelector
(
state
=>
state
.
cart
)
const
[
loading
,
setLoading
]
=
useState
(
0
)
useEffect
(()
=>
{
if
(
firstName
&&
lastName
&&
shippingAddress
&&
city
&&
state
&&
zipCode
)
{
...
...
@@ -73,11 +75,14 @@ export default function Checkout() {
userId
:
user
.
email
,
cartItems
:
[]
}
// clear user cart now that order has been placed
setLoading
(
1
)
dispatch
(
updateUserCart
(
cartUpdateObj
,
cartUpdateObj
.
userId
))
dispatch
(
storeCartItemsInProcessing
([]))
dispatch
(
calcTotalPrice
([]))
dispatch
(
calcNumItems
([]))
dispatch
(
calcTotalPromotions
([]))
}
else
{
setErrorWhileValidating
(
1
)
...
...
@@ -143,9 +148,11 @@ export default function Checkout() {
{
/* Displays info about order. Calculates price with tax / shipping applied */
}
<
ReviewOrder
numCartItems
=
{
numCartItems
}
promotionsDiscount
=
{
promotionsDiscount
}
itemsTotal
=
{
itemsTotal
}
shippingHandling
=
{
shippingHandling
}
taxRate
=
{
taxRate
}
loading
=
{
loading
}
/
>
{
/* Request to submit happens here, initiates input validation and sends if success */
}
<
SubmitOrder
...
...
ecom-web/src/components/shopping-cart/CartItem.js
View file @
5820e68d
...
...
@@ -27,7 +27,17 @@ export default function CartItem(props) {
<
/div
>
{
/* Price and promotions */
}
<
div
className
=
"priceAndPromotions"
>
<
div
className
=
"productPrice"
>
$
{
props
.
productInfo
.
price
.
toFixed
(
2
)}
<
/div
>
{
props
.
productInfo
.
promo
?
<
div
className
=
"productPrice"
>
<
span
style
=
{{
textDecoration
:
'line-through'
,
fontWeight
:
'normal'
}}
>
$
{(
props
.
quantity
*
props
.
productInfo
.
price
).
toFixed
(
2
)}
<
/span
>
<
span
style
=
{{
color
:
'green'
,
fontWeight
:
'bold'
}}
>
$
{(
props
.
quantity
*
props
.
productInfo
.
price
*
(
1.0
-
parseFloat
(
props
.
productInfo
.
promo
/
100.0
))).
toFixed
(
2
)}
<
/span
>
<
/div
>
:
<
div
className
=
"productPrice"
>
$
{(
props
.
quantity
*
props
.
productInfo
.
price
).
toFixed
(
2
)}
<
/div
>
}
<
/div
>
<
/div
>
)
...
...
ecom-web/src/components/shopping-cart/shopping-cart.css
View file @
5820e68d
...
...
@@ -32,6 +32,7 @@
padding-top
:
25px
;
margin-bottom
:
15px
;
font-size
:
125%
;
font-weight
:
bold
;
}
.productImageContainer
{
display
:
flex
;
...
...
@@ -66,6 +67,8 @@
margin-top
:
40px
;
font-size
:
125%
;
font-weight
:
bold
;
display
:
flex
;
flex-direction
:
column
;
}
.quantityControls
{
display
:
flex
;
...
...
ecom-web/src/components/shopping-cart/shopping-cart.js
View file @
5820e68d
...
...
@@ -4,13 +4,13 @@ import './shopping-cart.css'
import
{
useSelector
,
useDispatch
}
from
'react-redux'
import
{
Link
,
Redirect
}
from
'react-router-dom'
import
{
updateUserCart
}
from
'./../../actions/cart_actions'
import
{
calcTotalPrice
,
calcNumItems
,
storeCartItemsInProcessing
}
from
'./../../actions/cart_processing_actions'
import
{
calcTotalPrice
,
calcNumItems
,
storeCartItemsInProcessing
,
calcTotalPromotions
}
from
'./../../actions/cart_processing_actions'
export
default
function
ShoppingCart
()
{
const
dispatch
=
useDispatch
()
const
userSession
=
useSelector
(
state
=>
state
.
user
.
currentUser
)
const
allProducts
=
useSelector
(
state
=>
state
.
market
.
products
)
const
allPromotions
=
useSelector
(
state
=>
state
.
market
.
promotions
)
const
[
cartRefs
,
setCartRefs
]
=
useState
(
useSelector
(
state
=>
state
.
cart
))
const
[
cartItems
,
setCartItems
]
=
useState
([])
////////////////////////////////////////////////////////////////
...
...
@@ -66,6 +66,7 @@ export default function ShoppingCart() {
dispatch
(
storeCartItemsInProcessing
(
cartItems
))
dispatch
(
calcTotalPrice
(
cartItems
))
dispatch
(
calcNumItems
(
cartItems
))
dispatch
(
calcTotalPromotions
(
cartItems
))
},
[
cartItems
])
return
(
...
...
ecom-web/src/reducers/cart_processing_reducer.js
View file @
5820e68d
import
{
GET_TOTAL_PRICE
,
GET_NUM_ITEMS
,
GET_CART_PRODUCTS
}
from
'./../actions/cart_processing_actions'
import
{
GET_TOTAL_PRICE
,
GET_NUM_ITEMS
,
GET_CART_PRODUCTS
,
GET_TOTAL_PROMOTIONS
}
from
'./../actions/cart_processing_actions'
const
initialState
=
{
cartProducts
:
[],
numItems
:
0
,
totalPrice
:
0
totalPrice
:
0
,
totalPromotions
:
0
}
const
cartProcessingReducer
=
(
prevState
=
initialState
,
action
)
=>
{
...
...
@@ -25,6 +26,10 @@ const cartProcessingReducer = (prevState = initialState, action) => {
nextState
.
cartProducts
=
action
.
payload
return
nextState
case
GET_TOTAL_PROMOTIONS
:
nextState
.
totalPromotions
=
action
.
payload
return
nextState
default
:
return
nextState
...
...
ecom-web/src/util/cart_processing_util.js
View file @
5820e68d
...
...
@@ -10,3 +10,22 @@ export const numItemsCalcUtil = (productList) => {
console
.
log
(
"ITEMS IN CART: "
+
totalItems
)
return
totalItems
}
export
const
promoCalcUtil
=
(
productList
)
=>
{
const
totalSavings
=
productList
.
reduce
(
(
acc
,
curr
)
=>
{
let
temp
=
(
parseFloat
(
curr
.
product
.
price
)
*
parseFloat
(
curr
.
quantity
))
if
(
curr
.
product
.
promo
)
{
temp
=
temp
*
(
parseFloat
(
curr
.
product
.
promo
)
/
100.0
)
}
return
parseFloat
(
acc
)
+
temp
},
0
)
console
.
log
(
"PROMO SAVINGS: "
+
totalSavings
)
return
totalSavings
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment