Commit 7247dea3 authored by Christopher Cottier's avatar Christopher Cottier

Working master branch, connected to proction microservice endpoints, some...

Working master branch, connected to proction microservice endpoints, some local config would need to be changed to send to prod
parents 88b9f764 aaa23771
<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
...@@ -52,6 +52,11 @@ ...@@ -52,6 +52,11 @@
<artifactId>springfox-boot-starter</artifactId> <artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version> <version>3.0.0</version>
</dependency> </dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-core</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies> </dependencies>
......
...@@ -6,6 +6,7 @@ spring.data.mongodb.uri=mongodb+srv://ecom:ecom@e-commerce-db-cluster.va815.mong ...@@ -6,6 +6,7 @@ spring.data.mongodb.uri=mongodb+srv://ecom:ecom@e-commerce-db-cluster.va815.mong
spring.data.mongodb.database=e-commerce-db spring.data.mongodb.database=e-commerce-db
spring.data.mongodb.uri=mongodb+srv://ecom:ecom@e-commerce-db-cluster.va815.mongodb.net/e-commerce-db?retryWrites=true&w=majority
security.enable-csrf=false security.enable-csrf=false
server.port=8080 server.port=8080
...@@ -15,4 +16,4 @@ orders.apiUrl=http://138.91.251.222:8086 ...@@ -15,4 +16,4 @@ orders.apiUrl=http://138.91.251.222:8086
#products.apiUrl=http://localhost:8083 #products.apiUrl=http://localhost:8083
#promos.apiUrl=http://localhost:8082 #promos.apiUrl=http://localhost:8082
#orders.apiUrl=http://localhost:8084 #orders.apiUrl=http://localhost:8084
\ No newline at end of file
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
/node_modules /node_modules
/.pnp /.pnp
.pnp.js .pnp.js
package-lock.json
# testing # testing
/coverage /coverage
......
This diff is collapsed.
...@@ -11,11 +11,14 @@ ...@@ -11,11 +11,14 @@
"bootstrap": "^5.0.0", "bootstrap": "^5.0.0",
"jquery": "^3.6.0", "jquery": "^3.6.0",
"react": "^17.0.2", "react": "^17.0.2",
"react-animate-on-change": "^2.2.0",
"react-bootstrap": "^1.5.2", "react-bootstrap": "^1.5.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-google-login": "^5.2.2", "react-google-login": "^5.2.2",
"react-icons": "^4.2.0",
"react-modal": "^3.13.1", "react-modal": "^3.13.1",
"react-redux": "^7.2.4", "react-redux": "^7.2.4",
"react-router-bootstrap": "^0.25.0",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"redux": "^4.1.0", "redux": "^4.1.0",
......
...@@ -2,11 +2,16 @@ import {postUser} from '../util/session-api-util' ...@@ -2,11 +2,16 @@ import {postUser} from '../util/session-api-util'
export const SET_CURRENT_USER = "SET_CURRENT_USER" export const SET_CURRENT_USER = "SET_CURRENT_USER"
export const LOGOUT_USER = "LOGOUT_USER" export const LOGOUT_USER = "LOGOUT_USER"
export const SET_USER_IMAGE = "SET_USER_IMAGE"
export const setCurrentUser = (user) => { export const setCurrentUser = (user) => {
return {type: SET_CURRENT_USER, user} return {type: SET_CURRENT_USER, user}
} }
export const setUserImage = (image) => {
return {type: SET_USER_IMAGE, image}
}
export const logoutUser = () => { export const logoutUser = () => {
return {type: LOGOUT_USER} return {type: LOGOUT_USER}
} }
...@@ -17,6 +22,10 @@ export const login = (user) => dispatch => { ...@@ -17,6 +22,10 @@ export const login = (user) => dispatch => {
) )
) )
} }
export const addUserImage = image => dispatch => {
return dispatch(setUserImage(image))
}
// export const login = () => { // export const login = () => {
// return (dispatch) => { // return (dispatch) => {
// return dispatch(setCurrentUser()); // return dispatch(setCurrentUser());
......
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Header from './header'; import Header from './header';
import { clearUserCart } from '../../actions/cart_actions';
import { logOut } from '../../actions/session_actions';
const mSTP = state => ({ const mSTP = state => {
user: state.user return {
}); user: state.user,
cartLength: state.cart.length,
image: state.user?.userImage
}
};
const mDTP = dispatch => ({ const mDTP = dispatch => ({
logOut: () => dispatch(logOut()),
clearCart: () => dispatch(clearUserCart())
}); });
export default connect(mSTP, mDTP)(Header); export default connect(mSTP, mDTP)(Header);
\ No newline at end of file
/* .order-history-nav,
.products-nav, #header-nav {
#nav-bar-text,
.cart-nav {
padding-left: 10px;
padding-top: 11px;
padding-bottom: 10px;
color: white;
} */
.header-nav {
padding-left: 20px; padding-left: 20px;
box-shadow: 0px 1px 10px; box-shadow: 0px 1px 10px;
background-color: #00567D !important;
} }
/* #nav-home-link {
margin-bottom: 3px;
} */
.nav-bar-text { .nav-bar-text {
padding-right: 20px; padding: 2px 20px 0px;
}
.nav-bar-text-default {
padding: 12px 20px 0px;
}
#white-color,
#collasible-nav-dropdown,
.navbar-light .navbar-brand {
color: #EBEBEB;
transition: all 0.5s;
}
#white-color:hover {
cursor: default;
opacity: 1;
}
#ecom-title {
font-size: 20px;
color: #EBEBEB;
cursor: default;
position: absolute;
left: 50%;
margin-left: -50px;
}
.ms-auto navbar-nav {
align-items: center;
}
#user-image {
width: 40px;
margin: 0px 10px 4px;
border-radius: 20px;
}
#collasible-nav-dropdown:hover,
.navbar-light .navbar-brand:hover,
.cart-link:hover {
opacity: 1;
color: #CCCDCF;
}
.navbar-light .navbar-brand:focus {
color: #EBEBEB;
}
#collasible-nav-dropdown {
display: flex;
align-items: center;
}
#collasible-nav-dropdown {
padding: 0px;
}
.cart-link {
margin-right: 25px;
transition: all 0.5s;
}
#disabled-cart-link {
margin-right: 12px;
opacity: 0.3;
}
.cart-link-container {
position: relative;
}
.ms-auto {
position: relative;
}
.items-in-cart {
position: absolute;
right: 9px;
top: 1px;
padding: 0px 8px;
background-color: gray;
border-radius: 15px;
cursor: pointer;
}
.items-in-cart-animation {
animation: headShake;
animation-duration: 0.8s;
}
.no-show {
display: none;
}
.dropdown-menu {
right: 2px;
animation: fadeInUp;
animation-duration: 0.3s;
}
.dropdown-item {
display: flex;
justify-content: center;
} }
.dropdown-item a {
color: rgba(0, 0, 0, 0.74);
text-decoration: none;
}
\ No newline at end of file
...@@ -4,43 +4,98 @@ import Navbar from 'react-bootstrap/Navbar' ...@@ -4,43 +4,98 @@ 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 {NavLink} from 'react-router-dom'
import Session from '../session/session-container' import Session from '../session/session-container'
import HeaderCart from './header-cart-container' import {LinkContainer} from 'react-router-bootstrap'
import { AiOutlineShoppingCart } from 'react-icons/ai'
import AnimateOnChange from 'react-animate-on-change'
import { GoogleLogout } from 'react-google-login';
import './header.css'; import './header.css';
const clientId = `${process.env.REACT_APP_GOOGLE_CLIENT_ID}.apps.googleusercontent.com`;
export default class Header extends Component { export default class Header extends Component {
constructor(props) { constructor(props) {
super(props) super(props)
this.state = {} this.state = {
isLoggedIn: true
}
this.logOutSuccess = this.logOutSuccess.bind(this);
this.toggleLoggedIn = this.toggleLoggedIn.bind(this);
}
toggleLoggedIn() {
const prevState = this.state.isLoggedIn;
this.setState({ isLoggedIn: !prevState })
}
logOutSuccess = (response) => {
this.props.logOut()
this.props.clearCart()
this.toggleLoggedIn()
} }
render() { render() {
let userName let userName
if(!!this.props.user?.currentUser){ if (!!this.props.user?.currentUser){
userName = this.props.user.currentUser.firstName userName = this.props.user.currentUser.firstName
}else{ } else{
userName = "Guest" userName = "Guest"
} }
return ( return (
<div> <div>
<Navbar className = "header-nav" collapseOnSelect expand="sm" bg="light"> <Navbar id="header-nav" collapseOnSelect expand="sm" bg="light">
<Navbar.Brand>Ascend Ecommerce</Navbar.Brand> <LinkContainer to="/product-market" >
<Navbar.Brand>Ascend</Navbar.Brand>
</LinkContainer>
<div id="ecom-title">Ecommerce</div>
<Navbar.Toggle aria-controls="responsive-navbar-nav" /> <Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav"> <Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
<Nav.Link to="/product-market" id="nav-home-link">Home</Nav.Link>
<Nav.Link to="/product-market">Products</Nav.Link>
</Nav>
<Nav className="ms-auto"> <Nav className="ms-auto">
{!this.props.user?.currentUser ? {!this.props.user?.currentUser ?
<Navbar.Text className="nav-bar-text">Hello Guest</Navbar.Text> : <Navbar.Text className="nav-bar-text-default" id="white-color">Hello Guest</Navbar.Text> :
<NavDropdown className="nav-bar-text" title={"Hello "+userName} id="collasible-nav-dropdown"> <NavDropdown
className="nav-bar-text"
title={
<div>
<img id="user-image" src={ this.props.image } />
Hello {userName}
</div>
}
id="collasible-nav-dropdown"
>
<NavDropdown.Item ><NavLink to="/orders">Order History</NavLink></NavDropdown.Item> <NavDropdown.Item ><NavLink to="/orders">Order History</NavLink></NavDropdown.Item>
<NavDropdown.Item>
<GoogleLogout
clientId={clientId}
buttonText="Logout"
onLogoutSuccess={this.logOutSuccess}
render={props => (<div onClick={props.onClick}>Logout</div>)}
>
</GoogleLogout>
</NavDropdown.Item>
</NavDropdown> </NavDropdown>
} }
<Session className="nav-bar-text"/> {
<HeaderCart className="nav-bar-text"/> this.state.isLoggedIn ?
<Session className="nav-bar-text" toggleLoggedIn={ this.toggleLoggedIn } />
:
""
}
<LinkContainer to="/cart" >
<Nav.Link to="/cart" className="cart-link" id={this.props.user?.currentUser ? "" : "disabled-cart-link"} disabled={ !this.props.user?.currentUser }>
<AiOutlineShoppingCart fill="#EBEBEB" size={30} />
</Nav.Link>
</LinkContainer>
<AnimateOnChange
baseClassName="items-in-cart"
animationClassName="items-in-cart-animation"
animate={ this.props.diff != 0 }
>
<LinkContainer to="/cart" >
<Nav.Link to="/cart" className={ this.props.cartLength > 0 ? "items-in-cart" : "no-show" }>{ this.props.cartLength }</Nav.Link>
</LinkContainer>
</AnimateOnChange>
</Nav> </Nav>
</Navbar.Collapse> </Navbar.Collapse>
</Navbar> </Navbar>
......
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux' import { useSelector, useDispatch } from 'react-redux'
import ShippingAddress from './ShippingAddress.js' import ShippingAddress from './ShippingAddress.js'
import PaymentMethod from './PaymentMethod.js' import PaymentMethod from './PaymentMethod.js'
import ReviewOrder from './ReviewOrder.js' import ReviewOrder from './ReviewOrder.js'
...@@ -11,13 +10,8 @@ import {dispatchOrderInfo} from './../../actions/checkout_actions' ...@@ -11,13 +10,8 @@ import {dispatchOrderInfo} from './../../actions/checkout_actions'
import { Redirect } from 'react-router' import { Redirect } from 'react-router'
import { updateUserCart } from './../../actions/cart_actions' import { updateUserCart } from './../../actions/cart_actions'
import { calcTotalPrice, calcNumItems, storeCartItemsInProcessing } from './../../actions/cart_processing_actions' import { calcTotalPrice, calcNumItems, storeCartItemsInProcessing } from './../../actions/cart_processing_actions'
export default function Checkout() { export default function Checkout() {
const dispatch = useDispatch() const dispatch = useDispatch()
/////////////////////// ///////////////////////
// Shipping Info State // Shipping Info State
/////////////////////// ///////////////////////
...@@ -28,7 +22,6 @@ export default function Checkout() { ...@@ -28,7 +22,6 @@ export default function Checkout() {
// const [city, setCity] = useState("Santa Rosa") // const [city, setCity] = useState("Santa Rosa")
// const [state, setState] = useState("California") // const [state, setState] = useState("California")
// const [zipCode, setZipCode] = useState("90210") // const [zipCode, setZipCode] = useState("90210")
const [firstName, setFirstName] = useState("") const [firstName, setFirstName] = useState("")
const [lastName, setLastName] = useState("") const [lastName, setLastName] = useState("")
const [shippingAddress, setShippingAddress] = useState("") const [shippingAddress, setShippingAddress] = useState("")
...@@ -36,9 +29,6 @@ export default function Checkout() { ...@@ -36,9 +29,6 @@ export default function Checkout() {
const [city, setCity] = useState("") const [city, setCity] = useState("")
const [state, setState] = useState("") const [state, setState] = useState("")
const [zipCode, setZipCode] = useState("") const [zipCode, setZipCode] = useState("")
/////////////////////// ///////////////////////
// Billing Info State // Billing Info State
/////////////////////// ///////////////////////
...@@ -46,57 +36,43 @@ export default function Checkout() { ...@@ -46,57 +36,43 @@ export default function Checkout() {
const [cardHolderName, setCardHolderName] = useState(["Guy Fieri"]) const [cardHolderName, setCardHolderName] = useState(["Guy Fieri"])
const [expirationDate, setExpirationDate] = useState(["05/20206"]) const [expirationDate, setExpirationDate] = useState(["05/20206"])
const [cvv, setCVV] = useState(["123"]) const [cvv, setCVV] = useState(["123"])
/////////////////////// ///////////////////////
// Order Review / Summary State // Order Review / Summary State
/////////////////////// ///////////////////////
const numCartItems = useSelector(state => state.cartProcessing.numItems) const numCartItems = useSelector(state => state.cartProcessing.numItems)
const itemsTotal = useSelector(state => state.cartProcessing.totalPrice) const itemsTotal = useSelector(state => state.cartProcessing.totalPrice)
const taxRate = 0.0725 const taxRate = 0.0725
const shippingHandling = 9.00 const shippingHandling = 9.00
/////////////////////// ///////////////////////
// Submit Button State // Submit Button State
/////////////////////// ///////////////////////
const [submitButtonActive, setSubmitButtonActive] = useState(0) const [submitButtonActive, setSubmitButtonActive] = useState(0)
const [allFieldsValidated, setAllFieldsValidated] = useState(0) const [allFieldsValidated, setAllFieldsValidated] = useState(0)
const [errorWhileValidating, setErrorWhileValidating] = useState(0) const [errorWhileValidating, setErrorWhileValidating] = useState(0)
/////////////////////// ///////////////////////
// Form Submission State // Form Submission State
/////////////////////// ///////////////////////
const user = useSelector(state => state.user.currentUser) const user = useSelector(state => state.user.currentUser)
const cart = useSelector(state => state.cart) const cart = useSelector(state => state.cart)
useEffect(() => { useEffect(() => {
if (firstName && lastName && shippingAddress && city && state && zipCode) { if (firstName && lastName && shippingAddress && city && state && zipCode) {
console.log("All Fields Validated!") console.log("All Fields Validated!")
setAllFieldsValidated(1) setAllFieldsValidated(1)
} }
}, [firstName, lastName, shippingAddress, city, state, zipCode]) }, [firstName, lastName, shippingAddress, city, state, zipCode])
useEffect(() => { useEffect(() => {
if (submitButtonActive === 1) { if (submitButtonActive === 1) {
if (allFieldsValidated) { if (allFieldsValidated) {
setErrorWhileValidating(0) setErrorWhileValidating(0)
handleSubmit() handleSubmit()
console.log("Successful submission request") console.log("Successful submission request")
setSubmitButtonActive(0) setSubmitButtonActive(0)
const cartUpdateObj = { const cartUpdateObj = {
userId: user.email, userId: user.email,
cartItems: [] cartItems: []
} }
// clear user cart now that order has been placed // clear user cart now that order has been placed
dispatch(updateUserCart(cartUpdateObj, cartUpdateObj.userId)) dispatch(updateUserCart(cartUpdateObj, cartUpdateObj.userId))
dispatch(storeCartItemsInProcessing([])) dispatch(storeCartItemsInProcessing([]))
...@@ -109,14 +85,10 @@ export default function Checkout() { ...@@ -109,14 +85,10 @@ export default function Checkout() {
} }
} }
else { ; } else { ; }
}, [submitButtonActive]) }, [submitButtonActive])
let handleSubmit = () => { let handleSubmit = () => {
console.log("Submitting Order!")
let orderInfo = { let orderInfo = {
"user": { "user": {
"userId": user.userId, "userId": user.userId,
...@@ -138,9 +110,7 @@ export default function Checkout() { ...@@ -138,9 +110,7 @@ export default function Checkout() {
} }
} }
console.log(orderInfo)
dispatch(dispatchOrderInfo(orderInfo)) dispatch(dispatchOrderInfo(orderInfo))
} }
//redirect to order confirmation page once reponse is recieved //redirect to order confirmation page once reponse is recieved
...@@ -149,7 +119,6 @@ export default function Checkout() { ...@@ -149,7 +119,6 @@ export default function Checkout() {
return ( return (
<div id="checkout-container"> <div id="checkout-container">
{/* Collects User's shipping info */} {/* Collects User's shipping info */}
<ShippingAddress <ShippingAddress
captureFirstName={setFirstName} captureFirstName={setFirstName}
...@@ -160,7 +129,6 @@ export default function Checkout() { ...@@ -160,7 +129,6 @@ export default function Checkout() {
captureState={setState} captureState={setState}
captureZipCode={setZipCode} captureZipCode={setZipCode}
/> />
{/* Collects User's payment info */} {/* Collects User's payment info */}
<PaymentMethod <PaymentMethod
cardNumber={cardNumber} cardNumber={cardNumber}
...@@ -172,7 +140,6 @@ export default function Checkout() { ...@@ -172,7 +140,6 @@ export default function Checkout() {
captureExpirationDate={setExpirationDate} captureExpirationDate={setExpirationDate}
captureCVV={setCVV} captureCVV={setCVV}
/> />
{/* Displays info about order. Calculates price with tax / shipping applied */} {/* Displays info about order. Calculates price with tax / shipping applied */}
<ReviewOrder <ReviewOrder
numCartItems={numCartItems} numCartItems={numCartItems}
...@@ -180,7 +147,6 @@ export default function Checkout() { ...@@ -180,7 +147,6 @@ export default function Checkout() {
shippingHandling={shippingHandling} shippingHandling={shippingHandling}
taxRate={taxRate} taxRate={taxRate}
/> />
{/* Request to submit happens here, initiates input validation and sends if success */} {/* Request to submit happens here, initiates input validation and sends if success */}
<SubmitOrder <SubmitOrder
submitButtonActive={submitButtonActive} submitButtonActive={submitButtonActive}
...@@ -188,9 +154,6 @@ export default function Checkout() { ...@@ -188,9 +154,6 @@ export default function Checkout() {
errorWhileValidating={errorWhileValidating} errorWhileValidating={errorWhileValidating}
allFieldsValidated={allFieldsValidated} allFieldsValidated={allFieldsValidated}
/> />
</div> </div>
) )
} }
\ No newline at end of file
import { Component } from 'react';
import '../../resources/stylesheets/footer.css'
class Footer extends Component {
constructor(props) {
super(props)
this.state = {
}
}
render() {
return (
<div className="footer">
All Rights Reserved 2021
</div>
)
}
}
export default Footer
\ No newline at end of file
...@@ -8,7 +8,8 @@ export default class ProductItem extends Component { ...@@ -8,7 +8,8 @@ export default class ProductItem extends Component {
super(props) super(props)
this.state = { this.state = {
orderItemQuantity: 1, orderItemQuantity: 1,
showDetailsModal: false showDetailsModal: false,
addedToCart: false
} }
this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmit = this.handleSubmit.bind(this);
this.toggleDetailsModal = this.toggleDetailsModal.bind(this); this.toggleDetailsModal = this.toggleDetailsModal.bind(this);
...@@ -31,6 +32,11 @@ export default class ProductItem extends Component { ...@@ -31,6 +32,11 @@ export default class ProductItem extends Component {
handleSubmit(e, product) { handleSubmit(e, product) {
e.preventDefault(); e.preventDefault();
this.setState({ addedToCart: true })
setTimeout(() => {
this.setState({ addedToCart: false })
}, 3000);
const newCart = Object.assign({}, { const newCart = Object.assign({}, {
userId: this.props.user.currentUser.email, userId: this.props.user.currentUser.email,
cartItems: JSON.parse(JSON.stringify(this.props.cart)) // JSON.parse/stringify will deep-dup the object cartItems: JSON.parse(JSON.stringify(this.props.cart)) // JSON.parse/stringify will deep-dup the object
...@@ -94,13 +100,20 @@ export default class ProductItem extends Component { ...@@ -94,13 +100,20 @@ export default class ProductItem extends Component {
<p id="promo-show-text"> <p id="promo-show-text">
${ discount } ${ discount }
</p> </p>
</div> : "$" + this.props.item.price } </div> : <p id={ this.props.item.promo ? "promo-price-text" : "prod-price-text" }>${ this.props.item.price } </p> }
</div> </div>
{ this.props.item.promo ? { this.props.item.promo ?
<p id="prod-promotion"> <p id="prod-promotion">
{ "Save " + this.props.item.promo + "%!"} { "Save " + this.props.item.promo + "%!"}
</p> : ""} </p> : ""}
</div> </div>
<div style={{
display: this.state.addedToCart ? "block" : "none"
}}
className="added-to-cart-message"
>
Successfully added {this.state.orderItemQuantity} {this.props.item.productName}(s) to cart!
</div>
<form onSubmit={ e => this.handleSubmit(e, this.props.item) } className="add-cart-and-quantity"> <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 <br /> Add to Cart</p>} { this.props.user?.currentUser ? "" :<p id="please-log-in-notice">Log in to <br /> Add to Cart</p>}
<p id="quantity-text">Qty</p> <p id="quantity-text">Qty</p>
...@@ -136,6 +149,7 @@ export default class ProductItem extends Component { ...@@ -136,6 +149,7 @@ export default class ProductItem extends Component {
bottom: '0', bottom: '0',
marginLeft: "-325px", marginLeft: "-325px",
marginTop: "-320px", marginTop: "-320px",
padding: "0px",
width: '650px', width: '650px',
height: '600px', height: '600px',
background: 'white', background: 'white',
......
...@@ -38,8 +38,8 @@ export default class ProductMarket extends Component { ...@@ -38,8 +38,8 @@ export default class ProductMarket extends Component {
<div className="products-container"> <div className="products-container">
{this.props.products.map(prod => { {this.props.products.map(prod => {
return ( return (
<div className={prod.availableStock >= 0 ? "product-item-container" : "no-item"} key={ prod.sku }> <div className={prod.availableStock > 0 ? "product-item-container" : "no-item"} key={ prod.sku }>
{ prod.availableStock >= 0 ? "" : <p id="out-of-stock">- Out of Stock -</p> } { prod.availableStock > 0 ? "" : <p id="out-of-stock">- Out of Stock -</p> }
{ prod.productName ? { prod.productName ?
<ProductItem <ProductItem
item={ prod } item={ prod }
......
import React from 'react'; import React from 'react';
import { Provider } from 'react-redux' import { Provider } from 'react-redux';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom'; import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import SessionContainer from './session/session-container'; import SessionContainer from './session/session-container';
import ProductMarketContainer from './product-market/product-market-container'; import ProductMarketContainer from './product-market/product-market-container';
import ShoppingCartContainer from './shopping-cart/shopping-cart-container'; import ShoppingCartContainer from './shopping-cart/shopping-cart-container';
import CheckoutContianer from './checkout/checkout-container'; import CheckoutContianer from './checkout/checkout-container';
import Header from './Header/header-container' import Header from './header/header-container';
import OrderHistory from './order-history/order-history'; import OrderHistory from './order-history/order-history';
import OrderConfirmation from './order-confirmation/order-confirmation'; import OrderConfirmation from './order-confirmation/order-confirmation';
......
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Session from './session'; import Session from './session';
import {login, logOut} from '../../actions/session_actions'; import {login, logOut, addUserImage} from '../../actions/session_actions';
import { fetchUserCart, createUserCart, clearUserCart } from '../../actions/cart_actions'; import { fetchUserCart, createUserCart, clearUserCart } from '../../actions/cart_actions';
const mSTP = state => ({ const mSTP = state => ({
...@@ -9,6 +9,7 @@ const mSTP = state => ({ ...@@ -9,6 +9,7 @@ const mSTP = state => ({
const mDTP = dispatch => ({ const mDTP = dispatch => ({
login: (userResponse) => dispatch(login(userResponse)), login: (userResponse) => dispatch(login(userResponse)),
addUserImage: image => dispatch(addUserImage(image)),
logOut: () => dispatch(logOut()), logOut: () => dispatch(logOut()),
getUserCart: userId => dispatch(fetchUserCart(userId)), getUserCart: userId => dispatch(fetchUserCart(userId)),
createCart: newCart => dispatch(createUserCart(newCart)), createCart: newCart => dispatch(createUserCart(newCart)),
......
import React, { Component } from 'react' import React, { Component } from 'react'
import { GoogleLogin, GoogleLogout } from 'react-google-login'; import { GoogleLogin } from 'react-google-login';
import '../../resources/stylesheets/session.css' import '../../resources/stylesheets/session.css'
const clientId = `${process.env.REACT_APP_GOOGLE_CLIENT_ID}.apps.googleusercontent.com`; const clientId = `${process.env.REACT_APP_GOOGLE_CLIENT_ID}.apps.googleusercontent.com`;
...@@ -14,15 +14,16 @@ export default class Session extends Component { ...@@ -14,15 +14,16 @@ export default class Session extends Component {
this.loginSuccess = this.loginSuccess.bind(this) this.loginSuccess = this.loginSuccess.bind(this)
this.loginFailed = this.loginFailed.bind(this) this.loginFailed = this.loginFailed.bind(this)
this.logOutSuccess = this.logOutSuccess.bind(this)
} }
loginSuccess = (response) => { loginSuccess = (response) => {
console.log(response);
const {accessToken, tokenId, googleId: userId, profileObj} = response const {accessToken, tokenId, googleId: userId, profileObj} = response
const {email, familyName: lastName, givenName: firstName} = profileObj const {email, familyName: lastName, givenName: firstName, imageUrl} = profileObj
const userResponse = {idToken: tokenId, userId, email, firstName, lastName, accessToken} const userResponse = {idToken: tokenId, userId, email, firstName, lastName, accessToken}
this.props.login(userResponse) this.props.login(userResponse)
this.setState({logIn: true}) this.props.addUserImage(imageUrl)
this.props.toggleLoggedIn()
// try grabbing user cart // try grabbing user cart
this.props.getUserCart(email) this.props.getUserCart(email)
...@@ -40,29 +41,17 @@ export default class Session extends Component { ...@@ -40,29 +41,17 @@ export default class Session extends Component {
// console.log('Login failed: res:', response); // console.log('Login failed: res:', response);
return response return response
} }
logOutSuccess = (response) => {
this.props.logOut()
this.props.clearCart()
this.setState({logIn: false})
}
render() { render() {
return ( return (
<div className="google-login-button"> <div className="google-login-button">
{!this.state.logIn ? <GoogleLogin
<GoogleLogin clientId={clientId}
clientId={clientId} buttonText="Login"
buttonText="Login" onSuccess={this.loginSuccess}
onSuccess={this.loginSuccess} onFailure={this.loginFailed}
onFailure={this.loginFailed} cookiePolicy={'single_host_origin'}
cookiePolicy={'single_host_origin'} />
/> : <GoogleLogout
clientId={clientId}
buttonText="Logout"
onLogoutSuccess={this.logOutSuccess}
></GoogleLogout>
}
</div> </div>
) )
} }
......
import React from 'react' import React from 'react'
import './shopping-cart.css' import './shopping-cart.css'
export default function CartItem(props) { export default function CartItem(props) {
return ( return (
<div className="shoppingCartItem" > <div className="shoppingCartItem" >
{console.log(props.productInfo)}
{/* This is based on amazon's style */} {/* This is based on amazon's style */}
{/* Flex-Direction: Row */} {/* Flex-Direction: Row */}
{/* Left image div */} {/* Left image div */}
<div id="productImageContainer"> <div className="productImageContainer">
<img className="productImage" alt="" src={props.productInfo.productImageUrl} /> <img className="productImage" alt="Product" src={props.productInfo.productImageUrl} />
</div> </div>
{/* Name and Product details */} {/* Name and Product details */}
<div id="nameAndDetails"> <div className="nameAndDetails">
<div id="productName">{props.productInfo.productName}</div> <div className="productName">{props.productInfo.productName}</div>
<div id="productStock">{props.productInfo.availableStock} left in stock</div> <div className="productStock">{props.productInfo.availableStock} left in stock</div>
<div className="quantityControls"> <div className="quantityControls">
<input <input
className="productQuantitySelect" className="productQuantitySelect"
type="number" type="number"
...@@ -32,37 +22,13 @@ export default function CartItem(props) { ...@@ -32,37 +22,13 @@ export default function CartItem(props) {
max="99" max="99"
onChange={(e) => {props.handleQuantityUpdate(props.productInfo.sku, parseInt( e.target.value) )}} onChange={(e) => {props.handleQuantityUpdate(props.productInfo.sku, parseInt( e.target.value) )}}
/> />
<button onClick={() => { props.handleDelete(props.productInfo.sku) }}>Delete</button> <button onClick={() => { props.handleDelete(props.productInfo.sku) }}>Delete</button>
</div> </div>
</div> </div>
{/* Price and promotions */} {/* Price and promotions */}
<div id="priceAndPromotions"> <div className="priceAndPromotions">
<div id="productPrice">${props.productInfo.price.toFixed(2)}</div> <div className="productPrice">${props.productInfo.price.toFixed(2)}</div>
</div> </div>
</div> </div>
) )
} }
\ No newline at end of file
/*
brand
name
price
*/
\ No newline at end of file
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import ShoppingCart from './shopping-cart'; import ShoppingCart from './shopping-cart.js';
const mSTP = state => ({ const mSTP = state => ({
......
* { * {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
} }
#shoppingCartContainer { #shoppingCartContainer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
...@@ -11,11 +9,17 @@ ...@@ -11,11 +9,17 @@
height: 100vh; height: 100vh;
width: 100%; width: 100%;
} }
#cartItemList {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
margin-bottom: 100px;
}
.shoppingCartItem { .shoppingCartItem {
width: 80%; width: 80%;
min-height: 250px; min-height: 200px;
border-top: 2px solid black; border-top: 2px solid black;
display: flex; display: flex;
background-color: white; background-color: white;
...@@ -24,31 +28,33 @@ ...@@ -24,31 +28,33 @@
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.productName {
#productImageContainer { padding-top: 25px;
margin-bottom: 15px;
font-size: 125%;
}
.productImageContainer {
display: flex; display: flex;
width: 30%; width: 30%;
margin-right: 20px; margin-right: 20px;
max-height: 100%; max-height: 100%;
max-width: 100%; max-width: 100%;
} }
.productImage { .productImage {
display: flex; display: flex;
width: 100%; width: 100%;
padding: 15px;
/* height: auto; */ /* height: auto; */
/* max-height: 100%; */ /* max-height: 100%; */
} }
.nameAndDetails {
#nameAndDetails {
display: flex; display: flex;
width: 45%; width: 45%;
height: 200px; height: 200px;
flex-direction: column; flex-direction: column;
text-align: left; text-align: left;
} }
.priceAndPromotions {
#priceAndPromotions {
display: flex; display: flex;
width: 10%; width: 10%;
height: 200px; height: 200px;
...@@ -56,11 +62,33 @@ ...@@ -56,11 +62,33 @@
flex-direction: column; flex-direction: column;
align-items: flex-end; align-items: flex-end;
} }
.productPrice {
#productQuantitySelect { margin-top: 40px;
font-size: 125%;
font-weight: bold;
}
.quantityControls{
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-end;
}
.productQuantitySelect {
width: 40px; width: 40px;
} }
#checkoutButtonContainer {
width: 50%;
min-height: 100px;
display: flex;
justify-content: center;
align-items: center;
}
#checkoutButton {
width: 100%;
height: 100%;
background-color: black;
color: white;
font-size: 150%;
font-weight: bold;
margin-bottom: 100px;
}
\ No newline at end of file
...@@ -6,25 +6,18 @@ import { Link, Redirect } from 'react-router-dom' ...@@ -6,25 +6,18 @@ import { Link, Redirect } from 'react-router-dom'
import { updateUserCart} from './../../actions/cart_actions' import { updateUserCart} from './../../actions/cart_actions'
import { calcTotalPrice, calcNumItems, storeCartItemsInProcessing } from './../../actions/cart_processing_actions' import { calcTotalPrice, calcNumItems, storeCartItemsInProcessing } from './../../actions/cart_processing_actions'
export default function ShoppingCart() { export default function ShoppingCart() {
const dispatch = useDispatch() const dispatch = useDispatch()
const userSession = useSelector(state => state.user.currentUser) const userSession = useSelector(state => state.user.currentUser)
const allProducts = useSelector(state => state.market.products) const allProducts = useSelector(state => state.market.products)
const [cartRefs, setCartRefs] = useState(useSelector(state => state.cart)) const [cartRefs, setCartRefs] = useState(useSelector(state => state.cart))
const [cartItems, setCartItems] = useState([]) const [cartItems, setCartItems] = useState([])
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Map Product Refs to Products that exist in redux global state // Map Product Refs to Products that exist in redux global state
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
useEffect(() => { useEffect(() => {
const productsFromRefs = [] const productsFromRefs = []
cartRefs.map((cartRef) => { cartRefs.map((cartRef) => {
productsFromRefs.push(( productsFromRefs.push((
{ {
...@@ -32,31 +25,22 @@ export default function ShoppingCart() { ...@@ -32,31 +25,22 @@ export default function ShoppingCart() {
quantity: cartRef.quantity quantity: cartRef.quantity
})) }))
}) })
console.log("NEW PRODUCTS FROM REFS YO") console.log("NEW PRODUCTS FROM REFS YO")
console.log(productsFromRefs) console.log(productsFromRefs)
setCartItems(productsFromRefs) setCartItems(productsFromRefs)
}, [cartRefs]) }, [cartRefs])
//////////////////////////////// ////////////////////////////////
// Delete Item from Cart // Delete Item from Cart
//////////////////////////////// ////////////////////////////////
let handleDelete = (skuToBeDeleted) => { let handleDelete = (skuToBeDeleted) => {
const newCartRefs = cartRefs.filter((cartRef) => !(cartRef.productRef.sku === skuToBeDeleted)) const newCartRefs = cartRefs.filter((cartRef) => !(cartRef.productRef.sku === skuToBeDeleted))
setCartRefs(newCartRefs) setCartRefs(newCartRefs)
} }
//////////////////////////////// ////////////////////////////////
// Update Quantity of an item // Update Quantity of an item
//////////////////////////////// ////////////////////////////////
let handleQuantityUpdate = (skuToBeUpdated, newQuantity) => { let handleQuantityUpdate = (skuToBeUpdated, newQuantity) => {
const newCartRefs = [] const newCartRefs = []
cartRefs.map( (cartRef) => { cartRefs.map( (cartRef) => {
if (cartRef.productRef.sku === skuToBeUpdated) { if (cartRef.productRef.sku === skuToBeUpdated) {
let temp = cartRef let temp = cartRef
...@@ -67,35 +51,26 @@ export default function ShoppingCart() { ...@@ -67,35 +51,26 @@ export default function ShoppingCart() {
newCartRefs.push(cartRef) newCartRefs.push(cartRef)
} }
}) })
setCartRefs(newCartRefs) setCartRefs(newCartRefs)
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Sync Cart with backend and redux global state // Sync Cart with backend and redux global state
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
useEffect(() => { useEffect(() => {
if (!userSession) return; if (!userSession) return;
const cartUpdateObj = { const cartUpdateObj = {
userId: userSession.email, userId: userSession.email,
cartItems: cartRefs cartItems: cartRefs
} }
dispatch(updateUserCart(cartUpdateObj, cartUpdateObj.userId)) dispatch(updateUserCart(cartUpdateObj, cartUpdateObj.userId))
dispatch(storeCartItemsInProcessing(cartItems)) dispatch(storeCartItemsInProcessing(cartItems))
dispatch(calcTotalPrice(cartItems)) dispatch(calcTotalPrice(cartItems))
dispatch(calcNumItems(cartItems)) dispatch(calcNumItems(cartItems))
}, [cartItems]) }, [cartItems])
//if (!userSession) return <Redirect to="/product-market" />
return ( return (
<div id="shoppingCartContainer"> <div id="shoppingCartContainer">
{/* map each cart item into CartItem component */} {/* map each cart item into CartItem component */}
<div id="cartItemList"> <div id="cartItemList">
{cartItems.map((currItem) => { {cartItems.map((currItem) => {
return ( return (
......
import React, {useState, useEffect} from 'react'
import CartItem from './CartItem.js'
import './shopping-cart.css'
export default function ShoppingCart() {
const [cartItems, setCartItems] = useState([])
// load the json containing user's cart items
useEffect( () => {
setCartItems(
[
{
"id": 1,
"sku": 1,
"upc": 1,
"productName": "UMYOGO Mens Athletic Walking Blade Running Tennis Shoes",
"productDescription": "Rubber sole Rubber material of sole possesses high durability for prolonging the wearing time of our shoes.\nThe elastic blade soles have high flexibility which allows the shoes to bend strongly while doing sports.\nKnit upper material make it possible that your feet free breath when you run or walk.\nIt's soft and protective to cushion your every step",
"price": 45.00,
"availableStock": 100,
"blockedStock": 20,
"productImageUrl": "https://images-na.ssl-images-amazon.com/images/I/71djekdy4eL._AC_UY695_.jpg",
"brand": "UMYOGO",
"category": "shoe",
"quantity": 2
},
{
"id": 2,
"sku": 2,
"upc": 2,
"productName": "adidas Women's Cloudfoam Pure Running Shoe",
"productDescription": "100% Synthetic\nImported\nRubber sole\nPlatform measures approximately 0-3 inches\nBoot opening measures approximately 6-12 inches around\nWomen's specific fit\nCloudfoam memory sockliner and textile lining",
"price": 50.00,
"availableStock": 100,
"blockedStock": 20,
"productImageUrl": "https://images-na.ssl-images-amazon.com/images/I/71G0sB8FnFL._AC_UX695_.jpg",
"brand": "Adidas",
"category": "shoe"
},
{
"id": 3,
"sku": 3,
"upc": 3,
"productName": "Merrell Men's Moab 2 Vent Hiking Shoe",
"productDescription": "100% suede leather, mesh\nImported\nSynthetic sole\nPerformance suede leather and mesh upper\nBellows, closed-cell foam tongue keeps moisture and debris out",
"price": 100.00,
"availableStock": 100,
"blockedStock": 20,
"productImageUrl": "https://images-na.ssl-images-amazon.com/images/I/81m9GyEmoRL._AC_UX695_.jpg",
"brand": "Merrell",
"category": "shoe"
},
{
"id": 4,
"sku": 4,
"upc": 4,
"productName": "Nike Women's Training Basketball Shoe",
"productDescription": "Rubber\nBrand New\n100% Authentic\nOriginal Packaging",
"price": 85.00,
"availableStock": 100,
"blockedStock": 20,
"productImageUrl": "https://images-na.ssl-images-amazon.com/images/I/71zKmTHcHUL._AC_UX695_.jpg",
"brand": "Nike",
"category": "shoe"
},
{
"id": 5,
"sku": 5,
"upc": 5,
"productName": "adidas Men's Daily 3.0 Skate Shoe",
"productDescription": "100% Leather\nRubber sole\nadidas Mens Skate Shoe\nThe adidas brand has a long history and deep-rooted connection with sport. Everything we do is rooted in sport",
"price": 85.00,
"availableStock": 100,
"blockedStock": 20,
"productImageUrl": "https://images-na.ssl-images-amazon.com/images/I/71NVcBO0LEL._AC_UX695_.jpg",
"brand": "Adidas",
"category": "shoe"
},
{
"id": 6,
"sku": 6,
"upc": 6,
"productName": "Amazon Basics Lightweight Soft Easy Care Microfiber Pillowcases - 2-Pack, Black",
"productDescription": "100% Polyester\nImported\nIncludes two 20 x 30 inch standard-size pillowcases\nPolyester microfiber offers strength and exceptional softness",
"price": 8.99,
"availableStock": 100,
"blockedStock": 20,
"productImageUrl": "https://images-na.ssl-images-amazon.com/images/I/818vTEo5TPL._AC_SX679_.jpg",
"brand": "Amazon Basics",
"category": "pillow case"
},
{
"id": 7,
"sku": 7,
"upc": 7,
"productName": "Pillowcase Set of 2 Durable Chair Cushion, Chair Pad Filled Cotton",
"productDescription": "Comfortable Thickness: Seat pad with a thickness of 10 cm is sufficient to relieve stress, so if you sit for a long time, you will feel its warmth and softness.",
"price": 42.99,
"availableStock": 100,
"blockedStock": 20,
"productImageUrl": "https://images-na.ssl-images-amazon.com/images/I/61Txdww5uXS._AC_SX679_.jpg",
"brand": "PillowCase",
"category": "pillow case"
},
{
"id": 8,
"sku": 8,
"upc": 8,
"productName": "Amazon Basics Lightweight Soft Easy Care Microfiber Pillowcases - 2-Pack, Navy Blue",
"productDescription": "100% Polyester\nImported\nIncludes two 20 x 30 inch standard-size pillowcases\nPolyester microfiber offers strength and exceptional softness",
"price": 8.99,
"availableStock": 100,
"blockedStock": 20,
"productImageUrl": "https://images-na.ssl-images-amazon.com/images/I/81jZRRyZCfL._AC_SX679_.jpg",
"brand": "Amazon Basics",
"category": "pillow case"
},
{
"id": 9,
"sku": 9,
"upc": 9,
"productName": "Bedsure Bamboo Pillow Cases Queen Set of 2 - Cooling Ultra Soft Pillowcases",
"productDescription": "Bamboo-derived Rayon\nExceptionally Bamboo Texture: Bedsure queen Pillowcases layer your sleep space with an irresistibly sleek sateen finish to transform your bed into a luxurious retreat - Slip in feathery soft pillowcases to have a dreamy rest as if you are sleeping on a cloud and also wake up with cool feelings - Silky smooth to the touch, bamboo pillowcase queen glides over your hair and face to create a beauty sleep.",
"price": 11.04,
"availableStock": 100,
"blockedStock": 20,
"productImageUrl": "https://images-na.ssl-images-amazon.com/images/I/61IdiIz3qML._AC_SX679_.jpg",
"brand": "BedSure",
"category": "pillow case"
},
{
"id": 10,
"sku": 10,
"upc": 10,
"productName": "Amazon Basics Lightweight Soft Easy Care Microfiber Pillowcases - 2-Pack, Taupe",
"productDescription": "100% Polyester\nImported\nIncludes two 20 x 30 inch standard-size pillowcases\nPolyester microfiber offers strength and exceptional softness",
"price": 8.99,
"availableStock": 100,
"blockedStock": 20,
"productImageUrl": "https://images-na.ssl-images-amazon.com/images/I/91GB7gHxSuL._AC_SX679_.jpg",
"brand": "Amazon Basics",
"category": "pillow case"
}
]
)
}, [] )
return (
<div id="shoppingCartContainer">
{/* map each cart item into CartItem component */}
{cartItems.map( (currItem) => {
return (
<CartItem productInfo={currItem} />
)
})}
</div>
)
}
import {SET_CURRENT_USER, LOGOUT_USER} from '../actions/session_actions' import {SET_CURRENT_USER, LOGOUT_USER, SET_USER_IMAGE} from '../actions/session_actions'
const initialState = { const initialState = {
currentUser: null, currentUser: null,
userImage: null
} }
const userReducer = (state = initialState, action) => { const userReducer = (state = initialState, action) => {
...@@ -11,6 +12,9 @@ const userReducer = (state = initialState, action) => { ...@@ -11,6 +12,9 @@ const userReducer = (state = initialState, action) => {
case SET_CURRENT_USER: case SET_CURRENT_USER:
newState.currentUser = action.user.data; newState.currentUser = action.user.data;
return newState; return newState;
case SET_USER_IMAGE:
newState.userImage = action.image;
return newState;
case LOGOUT_USER: case LOGOUT_USER:
return newState.currentUser = null; return newState.currentUser = null;
default: default:
......
.footer {
height: 65px;
display: flex;
justify-content: center;
align-items: center;
background-color: #f8f9fa;
opacity: 0.4;
cursor: default;
}
\ No newline at end of file
...@@ -19,13 +19,15 @@ ...@@ -19,13 +19,15 @@
#product-market-title p { #product-market-title p {
width: 30%; width: 30%;
/* border-bottom: 1px solid black; */
} }
.products-container { .products-container {
width: 80%; width: 100%;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
margin-bottom: 30px;
} }
.product-item-container { .product-item-container {
...@@ -171,7 +173,7 @@ ...@@ -171,7 +173,7 @@
#promo-show { #promo-show {
display: flex; display: flex;
justify-content: center; justify-content: center;
margin-top: 5px; margin-top: 3px;
padding-top: 2px; padding-top: 2px;
height: 24px; height: 24px;
} }
...@@ -183,12 +185,12 @@ ...@@ -183,12 +185,12 @@
#promo-show-text-original { #promo-show-text-original {
text-decoration: line-through; text-decoration: line-through;
font-size: 15px; font-size: 15px;
padding-top: 4px; padding-top: 6px;
color: gray; color: gray;
} }
#promo-show-text { #promo-show-text {
font-size: 18px; font-size: 20px;
padding-top: 2px; padding-top: 2px;
} }
...@@ -257,8 +259,14 @@ ...@@ -257,8 +259,14 @@
#product-details-right { #product-details-right {
width: 35%; width: 35%;
border-left: 1px solid black; padding-right: 20px;
margin-left: 20px; background-color: rgba(202, 202, 202, 0.6);
}
#prod-price-text {
font-size: 27px;
padding-bottom: 6px;
margin-right: 7px;
} }
#prod-details-box { #prod-details-box {
...@@ -298,8 +306,9 @@ ...@@ -298,8 +306,9 @@
#prod-details-container { #prod-details-container {
width: 100%; width: 100%;
display: flex; display: flex;
justify-content: center;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center;
padding: 20px;
} }
#prod-details-img { #prod-details-img {
...@@ -347,10 +356,13 @@ ...@@ -347,10 +356,13 @@
position: absolute; position: absolute;
text-align: center; text-align: center;
width: 190px; width: 190px;
bottom: 86px;
left: 3px; left: 3px;
bottom: 89px;
height: 48px;
padding: 12px;
padding: 3px 10px; padding: 3px 10px;
border-radius: 5px; border-radius: 5px;
cursor: default;
background-color: rgb(248, 76, 76); background-color: rgb(248, 76, 76);
animation: fadeInUp; animation: fadeInUp;
...@@ -455,6 +467,7 @@ ...@@ -455,6 +467,7 @@
padding-top: 9px; padding-top: 9px;
margin-bottom: -4px; margin-bottom: -4px;
border-radius: 0px 0px 7px 7px; border-radius: 0px 0px 7px 7px;
position: relative;
} }
.price-and-promo { .price-and-promo {
...@@ -463,6 +476,22 @@ ...@@ -463,6 +476,22 @@
flex-wrap: wrap; flex-wrap: wrap;
} }
.added-to-cart-message {
position: absolute;
bottom: 310px;
left: 12px;
background: #00557da1;
color: white;
padding: 6px;
width: 305px;
text-align: center;
border-radius: 7px;
transition: all 0.5s;
animation: fadeInUp;
animation-duration: 0.5s;
}
#disabled { #disabled {
pointer-events: none; pointer-events: none;
} }
......
.google-login-button { .google-login-button {
margin-right: 20px; margin-right: 10px;
} }
.google-login-button button { .google-login-button button {
......
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