React-Redux Amazon Clone Project

Final Chapter

It Has been a journey at Flat Iron School, with many ups and downs without a doubt. Since the beginning of the course, I knew this is what I wanted to do and this final push to finish a 5-month extensive course where it consisted of code every single day sharpened my critical thinking skills as well as my coding skills.

Intro

For this project I wanted to do something special, Thinking about what other companies look for and what they might look for in a Software Engineer I decided to do an amazon clone with full payment functionality.

Lets Talk Code

to Start the project I ran

npx create-react-app Amazon-Clone

The way I decided to tackle this project was by splitting everything into sections. The way I started was with something simple and worked my way up therefore, I chose to start with the NavBar. Keeping it simple gave my NavBar a search bar and 3 options that can be customizable and hidden so users who aren't logged in have to Sign In or Sign up for them to use those features.

Next Step

The next step of this project I went with was I created the Home Page which I will be extracting the Products I need From my

Rails API’s

using

gem 'faker'

With this, I was able to extract my products and create multiple rows using a flexbox using these CSS settings below

.home {

  justify-content: center;
  margin-left: auto;
  margin-right: auto;
  max-width: 1500px;
}



.home__row {
  text-align: center;
  display: inline-block;
  z-index: 1;
  margin-left: 5px;
  margin-right: 5px;

}

.home__image {
  width: 100%;
  z-index: -1;
  margin-bottom: -150px;
  mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0));
}

.star{
  color: yellow;
  display: flex;
}
.product {
  text-align: left;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  margin: 10px;
  padding: 20px;
  width: 85%;
  max-height: 400px;
  min-width: 100px;
  background-color: white;
  z-index: 1;
}



.product > img {
  max-height: 200px;
  width: 100%;
  object-fit: contain;
  margin-bottom: 15px;
}

.product > button {
  background: #f0c14b;
  border: 1px solid;
  margin-top: 10px;
  border-color: #a88734 #9c7e31 #846a29;
  color: #111;
}

.product__price {
  margin-top: 5px;
}

.product_info {
  width: 100%;
  height: 100px;
  margin-bottom: 15px;
}

this enabled me to place the cards in a row with the customization I needed. For this Home page, I needed to have the cards ready right when the DOM loaded and With the skills, I Learned I understood that

ComponentDidMount

would be a good choice, making a fetch to my back end and have those products ready before the page fully loads.

Card Layout

On the Home page, the card layout had to be unique since Amazon carries a simple but eye-catching way of setting things up. Therefore, each Product card needed to have the image, title, rating, description, and add to button which is the call to action to enable customers for a quick add to cart for a quick purchase.

Add To Cart

referencing the above text the Add to cart had to be a dispatch action that enabled me to add the specific product with its attributes to a new array called basket so then later on I would be able to use it. I was able to learn Context, and redux-tool-kit so I did both but stuck with redux-tool-kit for project requirement purposes. The way the reducer is set up is unique and amazing since the state of this toolkit reducer is an updated state meaning we no longer need spread operators.

How I set my reducer

To enable redux-tool-kit we have to

npm install @reduxjs/toolkit react-redux

For documentation, you can click Here for a Quickstart.

this gives us access to a variety of tools such as

configureStore, createSlice, and createAsyncThunk

Which is what I needed to meet the requirements. For the reducer, I Had to think of each action that I Needed which where

addToBasket, removeFromCart, setUserDetails, setUser, emptyBasket

and this is how I set it up

const basketStore = createSlice({
  name: "basket",
  initialState:{
    basket: [],
    user: localStorage.user,
    userDetails: []
  },
  reducers:{
    addToBasket: (state, action) => {
      state.basket.push(action.payload)
    },
    removeFromCart: (state, action) => {
      const index = state.basket.findIndex(
        (basketItem) => basketItem.id === action.id)
      if (index >= 0){
        state.basket.splice(index,1);
          }else{
       console.warn("No Items Found with the Id of:", action.id)
      }
    },
    emptyBasket: (state, action) => {
      state.basket.clear()
    },
    setUser: (state, action) => {
      console.log(state,action, "kkk")
      state.user = action.payload
    },
    setUserDetails: (state, action) =>{
      state.userDetails.push(action.payload)
    }
  }
})

After all of this, I was able to implement the checkout functionality that enabled me to use stripe.

Setting up stripe

to set stripe up I needed to install two packages

npm install @stripe/react-stripe-js

and

npm install @stripe/stripe-js

this was needed to use certain elements to have stripe work. To make stripe fully functional I decided to use firebase to enable payment but used Rails to store my orders to later retrieve them. for firebase I had to install the firebase packages it gives you when creating a new app and doing

firebase init

this let me pick the option function which enabled me to set sort of like another back end but only for stripe. the function consisted of this code

const functions = require("firebase-functions");
const express = require('express');
const cors = require('cors')
const stripe = require("stripe")('ENV')

const app = express();

// - Middlewares
app.use(cors({ origin: true }));
app.use(express.json());

// - API routes
app.get("/", (request, response) => response.status(200).send("hello world"));

app.post("/payments/create", async (request, response) => {
  const total = request.query.total;

  console.log("total:", total);

  const paymentIntent = await stripe.paymentIntents.create({
    amount: total, // subunits of the currency
    currency: "usd",
  });

  // OK - Created
  response.status(201).send({
    clientSecret: paymentIntent.client_secret,
  });
});

// - Listen command
exports.api = functions.https.onRequest(app);

which connected firebase as a back end to send a request to stripe every time my functions fired.

Biggest Challenge

One of the biggest challenges I had coming into this project was trying to organize myself to do a step-by-step for this project. I have a strong tendency to overstress initial projects with a blank slate of code since I just learned that language. I’m still learning to understand when it’s okay to take a step back breathe and plan the code out and not just freestyle it and think one step at a time instead of ten.

Coding Biggest Challenge

For my project’s coding, the biggest challenge had to be implementing stripe. I started by trying to use rails as the back end to send requests but quickly found out that rails had many many extra steps to pull stripe off making firebase my second choice.

Grand Finally

To wrap things up, this has been an amazing journey from looking back 5 months ago and not understanding one single line of code to now reading it as if it was second nature to me. I was lucky enough to reach out to people in the class and make a strong foundation as well as my whole amazing Cohort and if I had the chance to re-live and do it from day one I would.

21