Commit fe877568 authored by Shaphen Pangburn's avatar Shaphen Pangburn

Merge branch 'AFP139-OrderPage-Cart-Promotions' into 'Dev'

Afp139 order page cart promotions

See merge request !31
parents 1e9f2de0 257b43e9
......@@ -41,7 +41,7 @@ public class ProductService {
public Flux<Promotion> getAllPromotions() {
return WebClient
.builder()
.baseUrl(promoManagementUrl)
.baseUrl("http://localhost:8082")
.build()
.get()
.uri("/api/promos")
......
......@@ -7,6 +7,10 @@ spring.data.mongodb.uri=mongodb+srv://ecom:ecom@e-commerce-db-cluster.va815.mong
spring.data.mongodb.database=e-commerce-db
security.enable-csrf=false
server.port=8080
#
#products.apiUrl=http://13.64.175.185:8080
#promos.apiUrl=http://40.118.215.99:8082
#orders.apiUrl=http://138.91.251.222:8086
# UNCOMMENT FOR PRODUCTION DEPLOYMENT
#products.apiUrl=http://13.64.175.185:8080
......
This diff is collapsed.
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)))
......
......@@ -9,10 +9,12 @@ const receiveAllProducts = products => ({
products
})
const receiveAllPromotions = promotions => ({
type: RECEIVE_ALL_PROMOTIONS,
promotions
})
const receiveAllPromotions = promotions => {
return {
type: RECEIVE_ALL_PROMOTIONS,
promotions
}
}
const receiveAllProductsAndPromotions = prodsAndPromos => ({
type: RECEIVE_ALL_PRODUCTS_AND_PROMOTIONS,
......
......@@ -121,4 +121,4 @@
.company-banner {
height: 50;
width: 100px;
}
\ No newline at end of file
}
......@@ -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>
)
......
......@@ -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: 10px;
margin-bottom: 15px;
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;
}
......@@ -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()
///////////////////////
......@@ -32,17 +32,18 @@ export default function Checkout() {
///////////////////////
// Billing Info State
///////////////////////
const [cardNumber, setCardNumber] = useState(["123456789"])
const [cardNumber, setCardNumber] = useState(["123456789123456"])
const [cardHolderName, setCardHolderName] = useState(["Guy Fieri"])
const [expirationDate, setExpirationDate] = useState(["05/20206"])
const [expirationDate, setExpirationDate] = useState(["05/2026"])
const [cvv, setCVV] = useState(["123"])
///////////////////////
// Order Review / Summary State
///////////////////////
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
......
......@@ -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>
)
......
......@@ -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;
......
......@@ -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 (
......
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
......
......@@ -10,3 +10,25 @@ 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
}
else {
return 0.0
}
}, 0)
console.log("PROMO SAVINGS: " + totalSavings)
return totalSavings
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment