<file_sep>import React, {useEffect} from 'react';
import PropTypes from 'prop-types';
import {useDispatch, useSelector} from 'react-redux';
import CardItem from './components/CartItem';
import {
  Grid,
  Typography,
  Card,
  CardHeader,
  CardContent,
  CardMedia,
} from '@material-ui/core';
import {addToCart, removeFromCart} from '../../actions/cartActions';

const Cart = ({match, location, history}) => {
  const productId = match.params.id;

  const qty = location.search ? Number (location.search.split ('=')[1]) : 1;
  //grabs qty data from route

  const dispatch = useDispatch ();

  const cart = useSelector (state => state.cart);

  const {cartItems} = cart;

  useEffect (
    () => {
      if (productId) {
        dispatch (addToCart (productId, qty));
      }
    },
    [dispatch, productId, qty]
  );

  const removeFromCartHandler = id => {
    dispatch (removeFromCart (id));
  };

  // const checkoutHandler = () => {
  //   history.push('/login?redirect=shipping')
  // }

  // const cartTotal = cartItems
  //   .map (item => {
  //     return item.sale_price * item.qty;
  //   })
  //   .reduce ((a, b) => {
  //     return a + b;
  //   });

  const getCartTotal = () => {
    let totalsArray = cartItems.map (item => {
      return item.sale_price * item.qty;
    });

    const sum = (acc, val) => {
      return acc + val;
    };

    const cartTotal = totalsArray.reduce (sum, 0);

    return cartTotal;
  };

  const showCartItems = cartItems.map (item => {
    return (
      <Grid item sm={4} key={item.product_id}>
        <CardItem
          name={item.name}
          img={item.product_img}
          description={item.description}
          sale_price={item.sale_price}
          rating={item.rating}
          qty={item.qty}
          onClick={() => removeFromCartHandler (item.product_id)}
        />
      </Grid>
    );
  });

  return (
    <Grid>
      <Grid>
        <Typography>
          Cart
        </Typography>
      </Grid>
      <Grid container>
        {showCartItems}
      </Grid>
      <Grid container>
        <Typography>
          Total Cost:{getCartTotal ()}
        </Typography>
      </Grid>
    </Grid>
  );
};

Cart.propTypes = {};

export default Cart;
<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import {Header, Footer} from '../../layout-components';
import {makeStyles} from '@material-ui/styles';

const useStyles = makeStyles (theme => ({
  main: {
    minHeight: '90vh',
    // marginLeft: '10vw',
    // marginRight: '10vw',
    // marginTop: '5vh',
  },
}));

const LandingLayout = ({children}) => {
  const classes = useStyles ();

  return (
    <div>
      <Header />
      <main className={classes.main}>

        {children}
      </main>
      <Footer />
    </div>
  );
};

LandingLayout.propTypes = {
  children: PropTypes.node,
};

export default LandingLayout;
<file_sep>export const imageOne =
  'https://res.cloudinary.com/ddj5orpun/image/upload/v1604023269/the-shop/alf-williamsen-e_IP-9e7-Rs-unsplash_3_hmroq4_ilimpg_bgvgw0.jpg';

export const imageTwo =
  'https://res.cloudinary.com/ddj5orpun/image/upload/v1604017094/the-shop/alf-williamsen-e_IP-9e7-Rs-unsplash_2_kv4zku.jpg';

export const imageThree =
  'https://res.cloudinary.com/ddj5orpun/image/upload/v1604019239/the-shop/sebastian-pociecha-5eUO24bIIqY-unsplash_po7f96.jpg';

export const imageFour =
  'https://res.cloudinary.com/ddj5orpun/image/upload/v1604022699/the-shop/alf-williamsen-e_IP-9e7-Rs-unsplash_3_hmroq4_1_fkxfes.jpg';

export const imageFive =
  'https://res.cloudinary.com/ddj5orpun/image/upload/v1604520667/the-shop/matt-rogers-9NcMCSLYGtA-unsplash_jdptwo.jpg';
<file_sep>import {createStore, combineReducers, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import {composeWithDevTools} from 'redux-devtools-extension';
import {
  productListReducer,
  productDetailsReducer,
} from './reducers/productReducers';
import {cartReducer} from './reducers/cartReducers';

const reducer = combineReducers ({
  productList: productListReducer,
  productDetails: productDetailsReducer,
  cart: cartReducer,
});

const cartItemsFromStorage = localStorage.getItem ('cartItems')
  ? JSON.parse (localStorage.getItem ('cartItems'))
  : [];

//stores items in cart into store

const initialState = {
  cart: {
    cartItems: cartItemsFromStorage,
  },
};

const middleware = [thunk];

const store = createStore (
  reducer,
  initialState,
  composeWithDevTools (applyMiddleware (...middleware))
);

export default store;
<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import {CircularProgress, Grid, Typography} from '@material-ui/core';
import {makeStyles} from '@material-ui/styles';

const useStyles = makeStyles (theme => ({
  root: {
    marginTop: '40vh',
  },
}));

const LoadingSpinner = props => {
  const classes = useStyles ();
  return (
    <Grid
      className={classes.root}
      container
      direction="row"
      justify="center"
      alignItems="center"
    >
      <CircularProgress />

    </Grid>
  );
};

LoadingSpinner.propTypes = {};

export default LoadingSpinner;
<file_sep>export {default as Main} from './Main';
export {default as LandingLayout} from './LandingLayout';
<file_sep>import React, {useEffect, useState} from 'react';
import PropTypes from 'prop-types';
import {useDispatch, useSelector} from 'react-redux';
import {useParams} from 'react-router-dom';
import {getProductDetails} from '../../actions/productActions';
import {makeStyles} from '@material-ui/styles';
import {
  Grid,
  Typography,
  Card,
  CardHeader,
  CardContent,
  CardMedia,
  Fade,
  Button,
  Select,
  FormControl,
  MenuItem,
  InputLabel,
  TextField,
} from '@material-ui/core';
import LoadingSpinner from '../../components/LoadingSpinner';
const useStyles = makeStyles (theme => ({
  card: {},
  img: {
    height: '65vh',
  },
  formControl: {
    margin: theme.spacing (2),
    minWidth: 120,
  },
}));

const Product = ({history, match}) => {
  const [qty, setQty] = useState (1);
  const {id} = useParams ();
  const classes = useStyles ();

  const dispatch = useDispatch ();

  useEffect (
    () => {
      dispatch (getProductDetails (id));
    },
    [dispatch, id]
  );

  const {loading, error, product} = useSelector (state => state.productDetails);

  const addToCartHandler = () => {
    history.push(`/cart/${match.params.id}?qty=${qty}`)
  }

  return loading
    ? <LoadingSpinner />
    : error
        ? <Typography>Error!</Typography>
        : <Grid container direction="row" spacing={2}>

            <Grid item md={8}>
              <Card className={classes.card}>

                <CardHeader title={product.name} />

                {product.product_img
                  ? <Fade in={true}>

                      <CardMedia
                        className={classes.img}
                        image={product.product_img}
                      />
                    </Fade>
                  : <Grid className={classes.img} />}

                <CardContent>

                  <Typography>
                    {product.description}
                  </Typography>

                </CardContent>

              </Card>
            </Grid>
            <Grid item md={4} container direction="column" spacing={2}>
              <Grid item>

                <Card>
                  <CardHeader title="Sizes WIP" />
                  <CardContent>
                    <Typography>
                      8
                    </Typography>
                    <Typography>
                      9
                    </Typography>
                    <Typography>
                      10
                    </Typography>

                  </CardContent>
                </Card>
              </Grid>

              <Grid item>

                <Card>
                  <CardContent>
                    <Grid container direction="column">
                      <Grid>
                        <Typography>
                          Price: {product.sale_price}
                        </Typography>
                      </Grid>
                      <Grid>
                        <Typography>
                          STATUS: IN STOCK
                        </Typography>
                      </Grid>
                      <Grid>
                        <TextField
                          label="Qty"
                          select
                          variant="outlined"
                          className={classes.formControl}
                          value={qty}
                          onChange={e => setQty (e.target.value)}
                        >

                          {[
                            ...Array (product.number_in_stock).keys (),
                          ].map (x => (
                            <MenuItem key={x + 1} value={x + 1}>
                              {x + 1}
                            </MenuItem>
                          ))}

                        </TextField>
                      </Grid>
                      <Grid>
                        <Button onClick={addToCartHandler}>
                          <Typography>
                            ADD TO CART
                          </Typography>
                        </Button>

                      </Grid>

                    </Grid>

                  </CardContent>
                </Card>
              </Grid>
            </Grid>

          </Grid>;
};

Product.propTypes = {};

export default Product;
<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import {makeStyles} from '@material-ui/styles';
import {
  Grid,
  Typography,
  Card,
  CardHeader,
  CardContent,
  CardMedia,
  Button,
  CardActionArea,
  // Divider,
} from '@material-ui/core';

const useStyles = makeStyles (theme => ({
  img: {
    height: '50vh',
  },
}));

const Item = ({id, name, img, description, sale_price, onClick, children}) => {
  const classes = useStyles ();
  return (
    <Card className={classes.card}>
      <CardActionArea onClick={onClick}>

        <CardHeader title={name} />

        <CardMedia className={classes.img} image={img} />

        <CardContent>
          <Typography>
            {sale_price}
          </Typography>
        </CardContent>
      </CardActionArea>
      {children}
    </Card>
  );
};

Item.propTypes = {};

export default Item;
<file_sep>import React, {useEffect} from 'react';
import {Router} from 'react-router-dom';
import {createBrowserHistory} from 'history';
import {ThemeProvider} from '@material-ui/styles';
// import validate from 'validate.js';
//redux
import {Provider} from 'react-redux';
// import store from './store';
// import {loadUser} from './actions/auth';
// import setAuthToken from './utils/setAuthToken';

import theme from './theme';
import 'react-perfect-scrollbar/dist/css/styles.css';
// import './assets/scss/index.scss';
// import validators from './common/validators';
import Routes from './Routes';

const browserHistory = createBrowserHistory ();

const App = () => {
  // useEffect(() => {
  //   setAuthToken(localStorage.token)
  //   store.dispatch(loadUser())
  // }, [])

  return (
    <ThemeProvider theme={theme}>
      <Router history={browserHistory}>
        <Routes />
      </Router>
    </ThemeProvider>
  );
};

export default App;

/**
 * temp:
 * 
 * <Provider store={store}>
      <ThemeProvider theme={theme}>
        <Router history={browserHistory}>
          <Routes />
        </Router>
      </ThemeProvider>
    </Provider>
 * 
 * 
 */
<file_sep>
export {default as Landing} from './Landing'
export {default as Products} from './Products'
export {default as Product} from './Product'
export {default as Cart} from './Cart'


<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import {
  Grid,
  Typography,
  Card,
  CardContent,
  CardMedia,
  Divider,
  Link,
  Button,
} from '@material-ui/core';
import {makeStyles} from '@material-ui/styles';
// import {useSelector, useDispatch} from 'react-redux';
// import {useParams} from 'react-router-dom';
import {useHistory} from 'react-router-dom';
import {
  // imageOne,
  // imageTwo,
  // imageThree,
  // imageFour,
  imageFive,
} from '../../constants/imageConstants';

const useStyles = makeStyles (theme => ({
  landing: {
    maxWidth: '100vw',
    overflow: 'hidden',
  },
  card: {
    backgroundColor: theme.palette.blueGrey.main,
  },

  landingImage: {
    // background: 'linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5))',
    // backgroundSize: 'cover',
    height: '95vh',
  },
  overlay: {
    position: 'absolute',
    // top: '13vh',
    bottom: '1px',
    paddingLeft: '70%',

    height: '100vh',
  },
  relativeGrid: {
    position: 'relative',
  },
  overlayTagline: {
    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    width: '400px',
    height: '100px',
    opacity: '90%',
  },
  overlayText: {
    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    background: 'white',
    width: '300px',
    height: '100px',
    opacity: '75%',
  },
}));

const Landing = props => {
  const classes = useStyles ();

  let history = useHistory ();

  const routeToProducts = () => {
    history.push (`/products`);
  };

  return (
    <Grid className={classes.landing}>

      <Grid container direction="column">
        <Card className={classes.relativeGrid}>
          <CardMedia className={classes.landingImage} image={imageFive} />
          <Grid
            container
            direction="column"
            justify="center"
            alignItems="center"
            className={classes.overlay}
          >
            <Grid>
              <Typography
                variant="h1"
                color="textSecondary"
                className={classes.overlayTagline}
              >
                Walking on air...
              </Typography>

            </Grid>

            <Grid>
              <Link onClick={routeToProducts}>
                <Button>
                  <Typography
                    variant="h3"
                    color="textPrimary"
                    className={classes.overlayText}
                  >
                    BUY NOW
                  </Typography>
                </Button>
              </Link>
            </Grid>

          </Grid>

        </Card>

      </Grid>
      <Grid
        container
        direction="column"
        justify="flex-start"
        alignItems="stretch"
        spacing={3}
      >

        <Grid item />
        <Grid item>
          <Card className={classes.card}>
            <CardContent>
              <Typography variant="h1" color="textSecondary">
                Bruh
              </Typography>
            </CardContent>
          </Card>
        </Grid>
        <Grid item>
          <Card className={classes.card}>
            <CardContent>
              <Typography variant="h1" color="textSecondary">
                Bruh
              </Typography>
            </CardContent>
          </Card>
        </Grid>
        <Grid item />

      </Grid>
    </Grid>
  );
};

Landing.propTypes = {};

export default Landing;
<file_sep>import React, {useEffect} from 'react';
import {useDispatch, useSelector} from 'react-redux';
import {useHistory} from 'react-router-dom';
import {getProducts} from '../../actions/productActions';
import {makeStyles} from '@material-ui/styles';
import PropTypes from 'prop-types';
import {
  Grid,
  Typography,
  Box,

  // Card,
  // CardContent,
  // CardMedia,
  // Divider,
} from '@material-ui/core';
import Item from '../../components/Item';
import LoadingSpinner from '../../components/LoadingSpinner';

const useStyles = makeStyles (theme => ({
  root: {},
  headerText: {
    paddingBottom: theme.spacing (3),
  },
}));

const Products = props => {
  const classes = useStyles ();

  let history = useHistory ();

  const dispatch = useDispatch ();

  const {loading, error, products} = useSelector (state => state.productList);

  useEffect (
    () => {
      dispatch (getProducts ());
    },
    [dispatch]
  );

  const showProducts = products.map (product => {
    const routeToProduct = () => {
      history.push (`/products/${product.id}`);
    };

    return (
      <Grid item sm={4} key={product.id}>
        <Item
          name={product.name}
          img={product.product_img}
          description={product.description}
          sale_price={product.sale_price}
          rating={product.rating}
          onClick={routeToProduct}
        />
      </Grid>
    );
  });

  return (
    <Grid className={classes.root}>
      <Box className={classes.headerText}>
        <Typography variant="h1">
          Latest Products
        </Typography>
      </Box>

      {loading
        ? <LoadingSpinner />
        : error
            ? <Typography>Error!!</Typography>
            : <Grid container direction="row" spacing={2}>

                {showProducts}
              </Grid>}

    </Grid>
  );
};

Products.propTypes = {};

export default Products;
<file_sep>import axios from 'axios';
import {
  CART_ADD_ITEM,
  CART_REMOVE_ITEM,
  CART_SAVE_SHIPPING_ADDRESS,
  CART_SAVE_PAYMENT_METHOD,
} from '../constants/cartConstants';

export const addToCart = (id, qty) => async (dispatch, getState) => {
  const {data} = await axios.get (`/api/v1/products/${id}`);

  dispatch ({
    type: CART_ADD_ITEM,
    payload: {
      product_id: data.id,
      name: data.name,
      product_img: data.product_img,
      sale_price: data.sale_price,
      number_in_stock: data.number_in_stock,
      qty,
    },
  });

  localStorage.setItem (
    'cartItems',
    JSON.stringify (getState ().cart.cartItems)
  );
};

export const removeFromCart = id => (dispatch, getState) => {
  dispatch ({
    type: CART_REMOVE_ITEM,
    payload: id,
  });

  localStorage.setItem (
    'cartItems',
    JSON.stringify (getState ().cart.cartItems)
  );
};
<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import {makeStyles} from '@material-ui/styles';
import {useHistory} from 'react-router-dom';
import Box from '@material-ui/core/Box';
import Container from '@material-ui/core/Container';
import {
  Grid,
  Button,
  AppBar,
  Toolbar,
  Typography,
  CssBaseline,
  useScrollTrigger,
} from '@material-ui/core';
import ShoppingCartIcon from '@material-ui/icons/ShoppingCart';
import PersonIcon from '@material-ui/icons/Person';

const useStyles = makeStyles (theme => ({
  appBar: {
    backgroundColor: theme.palette.white,
  },
}));

function ElevationScroll (props) {
  const {children} = props;
  // Note that you normally won't need to set the window ref as useScrollTrigger
  // will default to window.
  // This is only being set here because the demo is in an iframe.
  const trigger = useScrollTrigger ({
    disableHysteresis: true,
    threshold: 0,
  });

  return React.cloneElement (children, {
    elevation: trigger ? 4 : 0,
  });
}

const Header = props => {
  let history = useHistory ();

  const routeToCart = () => {
    history.push (`/cart`);
  };

  const classes = useStyles ();

  return (
    <React.Fragment>
      <CssBaseline />
      <ElevationScroll {...props}>
        <AppBar className={classes.appBar}>
          <Toolbar>
            <Grid container justify="flex-end" spacing={2}>
              <Grid item>
                <Button onClick={routeToCart}>
                  <ShoppingCartIcon />
                </Button>
              </Grid>
              <Grid item>
                <Button>
                  <PersonIcon />
                </Button>
              </Grid>

            </Grid>

          </Toolbar>
        </AppBar>
      </ElevationScroll>
      <Toolbar />
    </React.Fragment>
  );
};

Header.propTypes = {};

export default Header;
