Commit 1be1a354 authored by Kyle Muldoon's avatar Kyle Muldoon

Merge branch 'product-page-users-can-add-one-or-more-item-to-cart-with-a-button' into 'master'

Product page users can add one or more item to cart with a button

See merge request !11
parents 9725c51d 621928da
<component name="libraryTable">
<library name="Maven: com.fasterxml:classmate:1.5.1">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/classmate/1.5.1/classmate-1.5.1.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/classmate/1.5.1/classmate-1.5.1-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/classmate/1.5.1/classmate-1.5.1-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.github.classgraph:classgraph:4.8.83">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/github/classgraph/classgraph/4.8.83/classgraph-4.8.83.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/github/classgraph/classgraph/4.8.83/classgraph-4.8.83-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/github/classgraph/classgraph/4.8.83/classgraph-4.8.83-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.springfox:springfox-bean-validators:3.0.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-bean-validators/3.0.0/springfox-bean-validators-3.0.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-bean-validators/3.0.0/springfox-bean-validators-3.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-bean-validators/3.0.0/springfox-bean-validators-3.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.springfox:springfox-boot-starter:3.0.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-boot-starter/3.0.0/springfox-boot-starter-3.0.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-boot-starter/3.0.0/springfox-boot-starter-3.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-boot-starter/3.0.0/springfox-boot-starter-3.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.springfox:springfox-core:3.0.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-core/3.0.0/springfox-core-3.0.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-core/3.0.0/springfox-core-3.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-core/3.0.0/springfox-core-3.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.springfox:springfox-data-rest:3.0.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-data-rest/3.0.0/springfox-data-rest-3.0.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-data-rest/3.0.0/springfox-data-rest-3.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-data-rest/3.0.0/springfox-data-rest-3.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.springfox:springfox-oas:3.0.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-oas/3.0.0/springfox-oas-3.0.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-oas/3.0.0/springfox-oas-3.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-oas/3.0.0/springfox-oas-3.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.springfox:springfox-schema:3.0.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-schema/3.0.0/springfox-schema-3.0.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-schema/3.0.0/springfox-schema-3.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-schema/3.0.0/springfox-schema-3.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.springfox:springfox-spi:3.0.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-spi/3.0.0/springfox-spi-3.0.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-spi/3.0.0/springfox-spi-3.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-spi/3.0.0/springfox-spi-3.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.springfox:springfox-spring-web:3.0.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-spring-web/3.0.0/springfox-spring-web-3.0.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-spring-web/3.0.0/springfox-spring-web-3.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-spring-web/3.0.0/springfox-spring-web-3.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.springfox:springfox-spring-webflux:3.0.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-spring-webflux/3.0.0/springfox-spring-webflux-3.0.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-spring-webflux/3.0.0/springfox-spring-webflux-3.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-spring-webflux/3.0.0/springfox-spring-webflux-3.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.springfox:springfox-spring-webmvc:3.0.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-spring-webmvc/3.0.0/springfox-spring-webmvc-3.0.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-spring-webmvc/3.0.0/springfox-spring-webmvc-3.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-spring-webmvc/3.0.0/springfox-spring-webmvc-3.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.springfox:springfox-swagger2:3.0.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-swagger2/3.0.0/springfox-swagger2-3.0.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-swagger2/3.0.0/springfox-swagger2-3.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-swagger2/3.0.0/springfox-swagger2-3.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.springfox:springfox-swagger-common:3.0.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-swagger-common/3.0.0/springfox-swagger-common-3.0.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-swagger-common/3.0.0/springfox-swagger-common-3.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-swagger-common/3.0.0/springfox-swagger-common-3.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.springfox:springfox-swagger-ui:3.0.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-swagger-ui/3.0.0/springfox-swagger-ui-3.0.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-swagger-ui/3.0.0/springfox-swagger-ui-3.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/springfox/springfox-swagger-ui/3.0.0/springfox-swagger-ui-3.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.swagger.core.v3:swagger-annotations:2.1.2">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/swagger/core/v3/swagger-annotations/2.1.2/swagger-annotations-2.1.2.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/swagger/core/v3/swagger-annotations/2.1.2/swagger-annotations-2.1.2-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/swagger/core/v3/swagger-annotations/2.1.2/swagger-annotations-2.1.2-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.swagger.core.v3:swagger-models:2.1.2">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/swagger/core/v3/swagger-models/2.1.2/swagger-models-2.1.2.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/swagger/core/v3/swagger-models/2.1.2/swagger-models-2.1.2-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/swagger/core/v3/swagger-models/2.1.2/swagger-models-2.1.2-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.swagger:swagger-annotations:1.5.20">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/swagger/swagger-annotations/1.5.20/swagger-annotations-1.5.20.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/swagger/swagger-annotations/1.5.20/swagger-annotations-1.5.20-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/swagger/swagger-annotations/1.5.20/swagger-annotations-1.5.20-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: io.swagger:swagger-models:1.5.20">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/swagger/swagger-models/1.5.20/swagger-models-1.5.20.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/swagger/swagger-models/1.5.20/swagger-models-1.5.20-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/swagger/swagger-models/1.5.20/swagger-models-1.5.20-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: org.mapstruct:mapstruct:1.3.1.Final">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/mapstruct/mapstruct/1.3.1.Final/mapstruct-1.3.1.Final.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/mapstruct/mapstruct/1.3.1.Final/mapstruct-1.3.1.Final-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/mapstruct/mapstruct/1.3.1.Final/mapstruct-1.3.1.Final-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: org.springframework.plugin:spring-plugin-core:2.0.0.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/plugin/spring-plugin-core/2.0.0.RELEASE/spring-plugin-core-2.0.0.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/plugin/spring-plugin-core/2.0.0.RELEASE/spring-plugin-core-2.0.0.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/plugin/spring-plugin-core/2.0.0.RELEASE/spring-plugin-core-2.0.0.RELEASE-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Maven: org.springframework.plugin:spring-plugin-metadata:2.0.0.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/plugin/spring-plugin-metadata/2.0.0.RELEASE/spring-plugin-metadata-2.0.0.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/plugin/spring-plugin-metadata/2.0.0.RELEASE/spring-plugin-metadata-2.0.0.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/plugin/spring-plugin-metadata/2.0.0.RELEASE/spring-plugin-metadata-2.0.0.RELEASE-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
......@@ -2,11 +2,13 @@ package com.nisum.ecomservice.model;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class UserRequestBody {
String idToken;
String userId;
......
This diff is collapsed.
......@@ -5,7 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- allow ajax calls -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<!-- css animations -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
/>
<title>Ecommerce App</title>
</head>
<body>
......
import * as ApiUtil from '../util/cart_api_util';
export const RECEIVE_USER_CART = "RECEIVE_USER_CART";
export const CLEAR_USER_CART = "CLEAR_USER_CART";
const receiveUserCart = cart => ({
type: RECEIVE_USER_CART,
cart
})
export const clearUserCart = () => ({
type: CLEAR_USER_CART
})
export const fetchUserCart = userEmail => dispatch => ApiUtil.fetchUserCart(userEmail)
.then(cart => dispatch(receiveUserCart(cart)));
export const updateUserCart = (updatedCart, userEmail) => dispatch => ApiUtil.updateCart(updatedCart, userEmail)
.then(cart => dispatch(receiveUserCart(cart)));
export const createUserCart = newCart => dispatch => ApiUtil.createCart(newCart)
.then(res => res.json)
\ No newline at end of file
......@@ -26,4 +26,4 @@ export const fetchPromotions = () => dispatch => ApiUtil.fetchPromotions()
.then(promotions => dispatch(receiveAllPromotions(promotions)));
export const fetchProductsAndPromotions = () => dispatch => ApiUtil.fetchProductsAndPromotions()
.then(prodsAndPromos => dispatch(receiveAllProductsAndPromotions(prodsAndPromos)));
\ No newline at end of file
.then(prodsAndPromos => dispatch(receiveAllProductsAndPromotions(prodsAndPromos)));
.order-history-nav {
.order-history-nav,
.products-nav,
#nav-bar-text,
.cart-nav {
padding-left: 10px;
padding-top: 11px;
padding-bottom: 10px;
color: white;
}
.nav-home {
color: white;
font-size: 20px;
margin-left: 10px;
}
#nav-home-link {
margin-bottom: 3px;
}
#nav-bar-text {
opacity: 0.6;
cursor: default;
}
\ No newline at end of file
import React, { Component } from 'react'
import Nav from 'react-bootstrap/Nav'
import Navbar from 'react-bootstrap/Navbar'
import NavDropdown from 'react-bootstrap/NavDropdown'
// import NavDropdown from 'react-bootstrap/NavDropdown'
import {NavLink} from 'react-router-dom'
import Session from '../session/session-container'
......@@ -17,21 +17,19 @@ export default class Header extends Component {
return (
<div>
<Navbar collapseOnSelect expand="lg" bg="primary" variant="dark">
<Navbar.Brand href="#home">Ascend Ecommerce</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<NavLink to="/product-market" id="nav-home-link"><span className="nav-home">Ascend Ecommerce</span></NavLink>
<Navbar.Collapse id="responsive-navbar-nav">
<Nav >
<Navbar.Text>
<Navbar.Text id="nav-bar-text">
Hello Guest!
</Navbar.Text>
</Nav>
<NavLink to="/product-market"><span className="order-history-nav">Products</span></NavLink>
<NavLink to="/product-market"><span className="products-nav">Products</span></NavLink>
<NavLink to="/orders"><span className="order-history-nav">Order History</span></NavLink>
<NavLink to="/cart"><span className="cart-nav">Cart</span></NavLink>
<Nav className="ms-auto">
<Session />
<Nav.Link>
Cart
</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
......
import React, {useState, useEffect} from 'react'
// import React, {useState, useEffect} from 'react'
export default function PaymentMethod() {
return (
......
import React, {useState, useEffect} from 'react'
// import React, {useState, useEffect} from 'react'
export default function ReviewOrder() {
return (
......
import React, {useState, useEffect} from 'react'
// import React, {useState, useEffect} from 'react'
export default function ShippingAddress() {
return (
......
import React, {useState, useEffect} from 'react'
// import React, {useState, useEffect} from 'react'
export default function SubmitOrder() {
return (
......
import React, {useState, useEffect} from 'react'
import ShippingAddress from './ShippingAddress.js'
import PaymentMethod from './PaymentMethod.js'
import ReviewOrder from './ReviewOrder.js'
import SubmitOrder from './SubmitOrder.js'
// import React, {useState, useEffect} from 'react'
// import ShippingAddress from './ShippingAddress.js'
// import PaymentMethod from './PaymentMethod.js'
// import ReviewOrder from './ReviewOrder.js'
// import SubmitOrder from './SubmitOrder.js'
export default function checkout() {
......
......@@ -5,13 +5,38 @@ export default class ProductDetails extends Component {
super(props)
this.state = {}
}
handleSubmit(e, product) {
e.preventDefault();
const newCart = Object.assign({}, {
userId: this.props.user.currentUser.email,
cartItems: JSON.parse(JSON.stringify(this.props.cart)) // JSON.parse/stringify will deep-dup the object
})
const newCartItem = {
productRef: {
id: product.sku,
sku: product.sku,
upc: product.upc,
},
quantity: parseInt(this.state.orderItemQuantity)
}
newCart.cartItems.push(newCartItem);
this.props.addToCart(newCart, this.props.user.currentUser.email);
}
render() {
return (
<div className="product-details-container">
<div id="product-details-left">
<div id="prod-details-container">
<img alt="" src={ this.props.product.productImageUrl } id="prod-details-img" />
{
this.props.product.productImageUrl ?
<img alt="" src={ this.props.product.productImageUrl } id="prod-details-img" />
:
<div id="prod-details-no-img">
<p id="prod-details-no-image-display">- No Photo Available -</p>
</div>
}
<div id="prod-details-box">
<div id="details-brand-and-sku-box">
<p id="details-brand">{ this.props.product.brand }</p>
......@@ -26,8 +51,8 @@ export default class ProductDetails extends Component {
<div id="product-details-condenser">
<div id="prod-details-shipping">
<p id="express-shipping">Express shipping & free returns</p>
<p>Free Delivery: <span>Everywhere!</span></p>
<p>Get it by: <span>Never!</span></p>
<p id="free-delivery">Free Delivery: <span>Everywhere!</span></p>
<p id="get-it-by">Get it by: <span>Never!</span></p>
</div>
{
this.props.product.promo ?
......@@ -37,13 +62,21 @@ export default class ProductDetails extends Component {
<p id="prod-details-promo-original-price">Normally: ${ this.props.product.price }</p>
</div>
:
""
<p id="prod-details-original-price">Price: ${ this.props.product.price }</p>
}
<input type="number" id="prod-details-quantity" placeholder="Quantity" />
<button id="prod-details-add-to-cart">
Add to Cart
</button>
</div>
<form className="details-add-cart-and-quantity" onSubmit={ e => this.handleSubmit(e, this.props.product) }>
<input
type="number"
className="prod-details-quantity"
disabled={ !this.props.user?.currentUser }
placeholder="Quantity"
/>
<button className="prod-details-add-to-cart" disabled={ !this.props.user?.currentUser }>
Add to Cart
</button>
{ this.props.user?.currentUser ? "" :<p id="details-please-log-in-notice">Log in to Add to Cart</p>}
</form>
</div>
</div>
</div>
)
......
......@@ -7,8 +7,10 @@ export default class ProductItem extends Component {
constructor(props) {
super(props)
this.state = {
orderItemQuantity: 1,
showDetailsModal: false
}
this.handleSubmit = this.handleSubmit.bind(this);
this.toggleDetailsModal = this.toggleDetailsModal.bind(this);
}
......@@ -17,22 +19,68 @@ export default class ProductItem extends Component {
this.setState({ showDetailsModal: !prevState });
}
handleChange(type) {
return e => {
this.setState({ [type]: e.target.value })
}
}
calculateDiscount(price, discount) {
return (price * ((100 - discount) / 100)).toFixed(2);
}
handleSubmit(e, product) {
e.preventDefault();
const newCart = Object.assign({}, {
userId: this.props.user.currentUser.email,
cartItems: JSON.parse(JSON.stringify(this.props.cart)) // JSON.parse/stringify will deep-dup the object
})
for (let i = 0; i < newCart.cartItems.length; i++) {
let item = newCart.cartItems[i];
if(item.productRef.sku === product.sku) {
item.quantity += parseInt(this.state.orderItemQuantity)
this.props.addToCart(newCart, this.props.user.currentUser.email);
return;
}
}
const newCartItem = {
productRef: {
id: product.sku,
sku: product.sku,
upc: product.upc,
},
quantity: parseInt(this.state.orderItemQuantity)
}
newCart.cartItems.push(newCartItem);
this.props.addToCart(newCart, this.props.user.currentUser.email);
}
render() {
let discount = this.calculateDiscount(this.props.item.price, this.props.item.promo)
return (
<div className="product-item">
<div id="more-details-img-box">
<img
id="prod-img"
alt=""
src={ this.props.item.productImageUrl ? this.props.item.productImageUrl : "-no photo-" }
onClick={ this.toggleDetailsModal }
/>
<p onClick={ this.toggleDetailsModal } id="more-details-text">More Details</p>
{
this.props.item.productImageUrl ?
<img
id="prod-img"
alt=""
src={ this.props.item.productImageUrl }
onClick={ this.toggleDetailsModal }
/>
:
<div
id="no-image-found"
onClick={ this.toggleDetailsModal }
>
<p id="no-image-display">- No Photo Available -</p>
</div>
}
{
this.props.item.productImageUrl ?
<p onClick={ this.toggleDetailsModal } id="more-details-text">More Details</p>
: ""
}
</div>
<p id="prod-name">{ this.props.item.productName }</p>
<div id="prod-price">
......@@ -50,10 +98,18 @@ export default class ProductItem extends Component {
<p id="prod-promotion">
{ "Save " + this.props.item.promo + "% on this item!"}
</p> : ""}
<div className="add-cart-and-quantity">
<input id="order-quantity" type="number" placeholder="Qty" />
<span id="add-to-cart-button">Add to Cart</span>
</div>
<form onSubmit={ e => this.handleSubmit(e, this.props.item) } className="add-cart-and-quantity">
{ this.props.user?.currentUser ? "" :<p id="please-log-in-notice">Log in to Add to Cart</p>}
<input
className="order-quantity"
type="number"
placeholder="Qty"
disabled={ !this.props.user?.currentUser }
onChange={ this.handleChange("orderItemQuantity") }
value = { this.state.orderItemQuantity }
/>
<button disabled={ !this.props.user?.currentUser } className="add-to-cart-button">Add to Cart</button>
</form>
<Modal
id="product-details-modal"
......@@ -66,8 +122,8 @@ export default class ProductItem extends Component {
left: '50%',
right: '0',
bottom: '0',
marginLeft: "-346px",
marginTop: "-372px",
marginLeft: "-325px",
marginTop: "-320px",
width: '650px',
height: '600px',
background: 'white',
......@@ -80,7 +136,12 @@ export default class ProductItem extends Component {
}
}}
>
<ProductDetails product={ this.props.item } discount={ discount } />
<ProductDetails
product={ this.props.item }
discount={ discount }
user={ this.props.user }
addToCart={ this.props.addToCart }
/>
</Modal>
</div>
)
......
import { connect } from 'react-redux';
import ProductMarket from './product-market';
import { fetchProducts, fetchPromotions } from '../../actions/product_actions';
import { fetchUserCart, updateUserCart } from '../../actions/cart_actions';
const mSTP = state => ({
products: state.market.products,
promotions: state.market.promotions,
user: state.user,
cart: state.cart
});
const mDTP = dispatch => ({
getProducts: () => dispatch(fetchProducts()),
getPromotions: () => dispatch(fetchPromotions())
getPromotions: () => dispatch(fetchPromotions()),
getUserCart: userId => dispatch(fetchUserCart(userId)),
addCartItem: (updatedCart, userEmail) => dispatch(updateUserCart(updatedCart, userEmail))
});
export default connect(mSTP, mDTP)(ProductMarket);
\ No newline at end of file
......@@ -23,20 +23,29 @@ export default class ProductMarket extends Component {
products.forEach(prod => {
promotions.forEach(promo => {
if (prod.sku === promo.productSku) {
prod.promo = (promo.discountPercentage * 100);
prod.promo = (promo.discountPercentage);
}
});
});
return (
<div className="product-market-container">
<h1 id="product-market-title">Product Market</h1>
<div id="product-market-title">
<p>
Product Market
</p>
</div>
<div className="products-container">
{this.props.products.map(prod => {
return (
<div className={prod.productName ? "product-item-container" : "no-item"} key={ prod.sku }>
{ prod.productName ?
<ProductItem item={ prod }/>
<ProductItem
item={ prod }
cart={ this.props.cart }
user={ this.props.user }
addToCart={ this.props.addCartItem }
/>
:
<div className="product-item">
<p id="prod-not-available">This Product is No Longer Available</p>
......
......@@ -16,11 +16,7 @@ const Root = ({ store }) => (
<Route
exact path="/"
render={() => {
return (
// this.state.isUserAuthenticated ? // This can be changed for however our frontend user auth will operate
// <Redirect to="/product-market" /> :
<Redirect to="/product-market" />
)
return ( <Redirect to="/product-market" /> )
}}
/>
<Route path="/session" component={ SessionContainer } /> { /* this can be removed if never used */ }
......
import { connect } from 'react-redux';
import Session from './session';
import {login, logOut} from '../../actions/session_actions'
import {login, logOut} from '../../actions/session_actions';
import { fetchUserCart, createUserCart, clearUserCart } from '../../actions/cart_actions';
const mSTP = state => ({
currentUser: state.user
......@@ -8,7 +9,10 @@ const mSTP = state => ({
const mDTP = dispatch => ({
login: (userResponse) => dispatch(login(userResponse)),
logOut: () => dispatch(logOut())
logOut: () => dispatch(logOut()),
getUserCart: userId => dispatch(fetchUserCart(userId)),
createCart: newCart => dispatch(createUserCart(newCart)),
clearCart: () => dispatch(clearUserCart())
});
export default connect(mSTP, mDTP)(Session);
\ No newline at end of file
import React, { Component } from 'react'
import { GoogleLogin, GoogleLogout } from 'react-google-login';
import '../../resources/stylesheets/session.css'
const clientId = `${process.env.REACT_APP_GOOGLE_CLIENT_ID}.apps.googleusercontent.com`;
......@@ -16,16 +17,23 @@ export default class Session extends Component {
this.logOutSuccess = this.logOutSuccess.bind(this)
}
// componentDidMount(){
// this.props.logOut()
// }
loginSuccess = (response) => {
const {accessToken, tokenId, googleId: userId, profileObj} = response
const {email, familyName: lastName, givenName: firstName} = profileObj
const userResponse = {idToken: tokenId, userId, email, firstName, lastName, accessToken}
this.props.login(userResponse)
this.setState({logIn: true})
// try grabbing user cart
this.props.getUserCart(email)
.then(res => res.json)
.catch(err => {
const newCart = {
userId: email,
cartItems: []
}
this.props.createCart(newCart)
})
}
loginFailed = (response) => {
......@@ -34,12 +42,13 @@ export default class Session extends Component {
logOutSuccess = (response) => {
this.props.logOut()
this.props.clearCart()
this.setState({logIn: false})
}
render() {
return (
<div>
<div className="google-login-button">
{!this.state.logIn ?
<GoogleLogin
clientId={clientId}
......
import { RECEIVE_USER_CART, CLEAR_USER_CART } from '../actions/cart_actions';
const initialState = []
const cartReducer = (state = initialState, action) => {
Object.freeze(state);
let newState = Object.assign({}, state);
switch (action.type) {
case RECEIVE_USER_CART:
return newState.cart = action.cart.data.cartItems
case CLEAR_USER_CART:
return []
default:
return state;
}
}
export default cartReducer;
\ No newline at end of file
import { combineReducers } from 'redux';
import productsReducer from './products_reducer';
import userReducer from './user_reducer'
import cartReducer from './cart_reducer';
const rootReducer = combineReducers({
market: productsReducer,
user: userReducer,
cart: cartReducer
});
export default rootReducer;
\ No newline at end of file
import {SET_CURRENT_USER, LOGOUT_USER} from '../actions/session_actions'
const initialState = {currentUser: null}
const initialState = {
currentUser: null,
}
const userReducer = (state = initialState, action) => {
Object.freeze(state);
let newState = Object.assign({}, state);
switch (action.type) {
case SET_CURRENT_USER:
return newState.currentUser = action.user.data;
newState.currentUser = action.user.data;
return newState;
case LOGOUT_USER:
return newState.currentUser = null;
default:
return state;
}
......
......@@ -7,12 +7,17 @@
#product-market-title {
width: 100%;
display: flex;
justify-content: center;
text-align: center;
font-size: 30px;
margin: 15px 0px 10px;
cursor: default;
border-bottom: 1px solid black;
padding-bottom: 15px;
padding: 15px 0px;
}
#product-market-title p {
width: 30%;
}
.products-container {
......@@ -52,6 +57,15 @@
transition: all 0.3s;
}
#no-image-found {
height: 200px;
width: 100%;
transition: all 0.3s;
display: flex;
justify-content: center;
align-items: center;
}
#more-details-img-box {
width: 100%;
display: flex;
......@@ -101,7 +115,7 @@
color: red;
}
#add-to-cart-button {
.add-to-cart-button {
cursor: pointer;
margin-bottom: 10px;
padding: 5px 40px;
......@@ -112,7 +126,7 @@
transition: all 0.3s;
}
#add-to-cart-button:hover {
.add-to-cart-button:hover {
background-color: rgb(207, 205, 205);
}
......@@ -143,26 +157,42 @@
padding-top: 2px;
}
#order-quantity {
width: 23px;
height: 13px;
.order-quantity {
border: 1px dotted rgba(0,0,0,0.3);
color: rgb(29, 29, 29);
border-radius: 5px;
margin-top: 2px;
margin: 1px 5px;
padding: 6px;
}
#order-quantity {
border: 1px dotted rgba(0,0,0,0.3);
outline: none;
color: rgb(29, 29, 29);
height: 30px;
padding: 6px;
width: 42px;
transition: all 0.5s;
}
#order-quantity:focus {
.order-quantity:focus {
border: 1px solid black;
}
.add-cart-and-quantity {
display: flex;
position: relative;
}
#please-log-in-notice {
display: none;
position: absolute;
bottom: 47px;
left: 22px;
padding: 3px 10px;
border-radius: 5px;
background-color: rgb(248, 76, 76);
animation: fadeInUp;
animation-duration: 0.5s;
}
.add-cart-and-quantity:hover #please-log-in-notice {
display: block;
}
#product-details-modal {
......@@ -237,6 +267,25 @@
height: 65%;
}
#no-image-display {
font-size: 20px;
opacity: 0.6;
}
#prod-details-no-image-display {
font-size: 28px;
opacity: 0.5;
cursor: default;
}
#prod-details-no-img {
width: 100%;
height: 65%;
display: flex;
justify-content: center;
align-items: center;
}
#prod-info-container {
width: 100%;
text-align: center;
......@@ -247,9 +296,29 @@
}
#product-details-condenser {
height: 28%;
position: relative;
height: 48%;
width: 100%;
margin: 185px 0px 0px 20px;
margin: 148px 0px 0px 20px;
}
#details-please-log-in-notice {
display: none;
position: absolute;
text-align: center;
width: 190px;
bottom: 86px;
left: 3px;
padding: 3px 10px;
border-radius: 5px;
background-color: rgb(248, 76, 76);
animation: fadeInUp;
animation-duration: 0.5s;
}
.details-add-cart-and-quantity:hover #details-please-log-in-notice {
display: block;
}
#prod-details-shipping {
......@@ -272,26 +341,40 @@
}
#express-shipping {
font-size: 14.3px;
font-size: 13.8px;
margin-bottom: 10px;
}
#prod-details-quantity {
#free-delivery {
font-size: 15.5px;
}
#get-it-by {
text-align: left;
width: 100%;
}
.details-add-to-cart-and-quantity {
position: relative;
}
.prod-details-quantity {
border: 1px dotted rgba(0,0,0,0.3);
border-radius: 5px;
outline: none;
margin-left: 3px;
color: rgb(29, 29, 29);
transition: all 0.5s;
}
#prod-details-quantity:focus {
.prod-details-quantity:focus {
border: 1px solid black;
}
#prod-details-add-to-cart {
.prod-details-add-to-cart {
cursor: pointer;
padding: 5px 40px;
margin: 10px 2px;
margin: 10px 3px;
width: 98%;
border-radius: 5px;
border: 1px solid black;
......@@ -300,7 +383,7 @@
transition: all 0.3s;
}
#prod-details-add-to-cart:hover {
.prod-details-add-to-cart:hover {
background-color: rgb(207, 205, 205);
}
......@@ -318,6 +401,13 @@
margin-bottom: 10px;
}
#prod-details-original-price {
text-align: center;
font-size: 17px;
margin-bottom: 10px;
color: red;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
......
.google-login-button {
margin-right: 20px;
}
.google-login-button button {
border-radius: 25px;
}
\ No newline at end of file
import axios from 'axios';
export const fetchUserCart = userEmail => {
return axios.get(`http://localhost:8080/api/carts/${userEmail}`)
}
export const createCart = newCart => {
return axios.post(`http://localhost:8080/api/carts`, newCart)
}
export const updateCart = (updatedCart, userEmail) => {
// debugger
return axios.put(`http://localhost:8080/api/carts/${userEmail}`, updatedCart)
}
\ 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