Building an Ionic 3 Shopping Cart App with Firebase Realtime Database - Part 4





In part three of this tutorial series, we stopped at creating the cart provider. Lets start by creating the cart page. By the time we finished the cart page, the result will look like what we have below.



The Cart Page

Create an ionic page named cart using the cli command like so:
ionic g page cart

Replace the html code with the following codes:

  
    
    
      Your Cart
    
  


  

Your cart is empty

{{itm.name}}


Qty: {{itm.count}}
Next is the scss file to make it look good. Add the below css code to the cart.scss file:
page-cart {
     .fixed-content,
     .scroll-content {
          background: #EAEAEA;

          .empty-cart{
               margin-top: 50%;
               height: 100%;
               .empty-results{
                    ion-icon{
                         font-size: 105px;
                         color: rgb(175, 175, 175);
                    }

                    p{
                         font-size: 30px;
                         color: rgb(175, 175, 175);
                    }
               }
          }


          ion-card {
               margin: 10px 0;
               width: 100%;
               min-height: 85px !important;
               ion-card-content {
                    padding: 8px !important;
                    ion-col {
                         padding: 0;
                         span.price {
                              right: 0;
                              position: absolute;
                              bottom: 0;
                         }
                         span.remove {
                              left: 0;
                              position: absolute;
                              bottom: 0;
                              background: #ff0000;
                              padding: 3px 10px;
                              color: #fff;
                         }
                         ion-item {
                              min-height: 75px !important;
                              padding: 0 !important;
                              .item-inner {
                                   padding: 0 !important;
                                   ion-label {
                                        min-height: 75px !important;
                                        margin: 0 !important;
                                        ion-avatar {
                                             min-height: 75px !important;
                                             img {
                                                  border-radius: 0 !important;
                                                  width: 80%;
                                                  height: 70px;
                                                  margin-right: 0 !important;
                                             }
                                        }
                                   }
                              }
                         }
                    }
               }
          } //End Ion-Card
          ion-card:first-child {
               margin-top: 0 !important;
          }
     }
     ion-footer.single-footer {
          background: #ECECE2;
     }
}


The Cart.ts File

Let's start by adding all the required imports.

import { CartProvider } from "../../providers/cart/cart";
import firebase from "firebase";
As you can see, I started by importing the CartProvider followed by firebase. We will also be using some variables, so let's declare them:
 cartItems: any[] = [];
  totalAmount: number = 0;
  isCartItemLoaded: boolean = false;
  isEmptyCart: boolean = true;

1. cartItems of type array which will hold the items that are added to cart.
2. totalAmount: of type number which holds the total amount of products in cart.
3. isCartItemLoaded of type boolean which will help detect if cart items has been loaded.
4. isEmptyCart of type boolean which will help detect if there are no items in the cart

The loadCartItems method will be responsible for loading items in cart as the name suggested.

loadCartItems() {
    let loader = this.loadingCtrl.create({
      content: "Wait.."
    });
    loader.present();
    this.cartService
      .getCartItems()
      .then(val => {
        this.cartItems = val;

        if (this.cartItems.length > 0) {
          this.cartItems.forEach((v, indx) => {
            this.totalAmount += parseInt(v.totalPrice);
          });
          this.isEmptyCart = false;
        }

        this.isCartItemLoaded = true;
        loader.dismiss();
      })
      .catch(err => {});
  }

The function is pretty simple, we are just making a call to the getCartItems in the CartProvider service, and then sends the returned array of items to the cartItems variable so that we can use it in our cart.html page.

It then also check if the returned array has record or not, if there are items in the array we move on to calculate the total amount by looping through the items then set the isEmptyCart variable to false.

There is also need for buyers to be able to remove item from cart so lets make another method to handle that.

 removeItem(itm) {
    this.cartService.removeFromCart(itm).then(() => {
      this.loadCartItems();
    });
  }

The method just call the removeFromCart method in our CartProvider service.

The last method in the .ts file is the checkoout. This will be called when the checkout button is clicked.

  checkOut() {
    var user = firebase.auth().currentUser;
    if (user) {
      this.navCtrl.push("CheckoutPage");
    } else {
      this.navCtrl.setRoot("LoginPage");
    }
  }

In this method, we took advantage of firebase auth to check if the current user is logged in or not. If logged in it sends user to checkout page if not the user is sent to login page.

The Checkout Page

The checkout page is a place where order and payment information will be displayed for a logged in user in other to proceed to making payment. Our checkout page will look like so:


As always let's start by necessary imports for the checkout page.

import firebase from "firebase";
import { CartProvider } from "../../providers/cart/cart";
import { AuthProvider } from "../../providers/auth/auth";
import { OrderProvider } from "../../providers/order/order";

And all the variables needed
 cartItems: any[] = [];
  productAmt: number = 0;
  totalAmount: number = 0;
  shippingFee: number = 20;
  customerName: any;
We have imported OrderProvider and AuthProvider that has not been created, let's create the OrderProvider and AuthProvider like so:
ionic g provider Order
ionic g provider Auth

 The OrderProvider

Open up the OrderProvider and let's add some codes.

Make reference to firebase orders and orderdetails like so:
firedata = firebase.database().ref("/orders");
  orderDetails = firebase.database().ref("/ordersdetails");

The only public method here will be the placeOrder which will be called whenever the place order button is clicked in the checkout page
  placeOrder(orderObj: any) {
    var promise = new Promise((resolve, reject) => {
      let orderRef = this.makeid(10);
      let orderObject = {
        orderRef: orderRef,
        customerName: orderObj.name || "",
        ShippingAmt: orderObj.shipping,
        OrderAmt: orderObj.orderAmount,
        totalAmount: orderObj.amount
      };

      this.firedata.push(orderObject).then(() => {
        orderObj.orders.forEach((v, indx) => {
          this.orderDetails
            .push({
              orderRef: orderRef,
              productName: v.name,
              Qty: v.count,
              amount: v.totalPrice
            })
            .then(() => {
              resolve(true);
            });
        });
      });
    });
    return promise;
  }

This method accept order object that will be sent from the checkout page. As you can see, it took care of order and order details.
The order object has Order Ref, Custmer Name, Shipping, and Amount while the order details object contains the Order Ref, Product Name, Count and the total amount. There is just one private method that generated order ref.
makeid(lenght: number) {
    var text = "";
    var possible =
      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    for (var i = 0; i < lenght; i++)
      text += possible.charAt(Math.floor(Math.random() * possible.length));

    return text;
  }

The AuthProvider 

This service has three methods namely login, registerUser and getuserdetails. The methods names are descriptive enough to explain their roles. Open the AuthProvider and add these three methods like so:
 
  login(loginParams){
    var promise = new Promise((resolve, reject) => {
      firebase.auth().signInWithEmailAndPassword(loginParams.email, loginParams.password).then(() => {
        resolve(true);
      }).catch((err) => {
        reject(err);
       })
    })

    return promise;
  }

  registerUser(userObj: any) {
    var promise = new Promise((resolve, reject) => {
      firebase .auth().createUserWithEmailAndPassword(userObj.email, userObj.password)
        .then(() => {
          this.firedata.child(firebase.auth().currentUser.uid).set({
            name:userObj.name,
            address:userObj.address,
            email:userObj.email
          }).then(()=>{
            resolve({ success: true });
          }).catch((err)=>{
            reject(err);
          })
         // resolve(true);
        })
        .catch(err => {
          reject(err);
        });
    })
    return promise;
  }

  getuserdetails() {
    var promise = new Promise((resolve, reject) => {
    this.firedata.child(firebase.auth().currentUser.uid).once('value', (snapshot) => {
      resolve(snapshot.val());
    }).catch((err) => {
      reject(err);
      })
    })
    return promise;
  }

The CheckOut.ts File 

Now that we have created the two providers needed in our checkout page let's now check out the code in the .ts file.

Our first task is to make sure that only logged in users are allowed to get to the checkout page, so we need to check first in the ionicViewWillEnter like so:
 
ionViewWillEnter() {

    var user = firebase.auth().currentUser;

    if (!user) this.navCtrl.setRoot("LoginPage");

  }


Our second task is to display the order information on the page. To achieve this, we will be calling two methods from our providers - getCartItems from cartProvider and getUserDetails from AuthProvider.
 

  loadCartItems() {
    let loader = this.loadingCtrl.create({
      content: "Wait.."
    });
    loader.present();
    this.cartService .getCartItems() .then(val => {
        this.cartItems = val;
        if (this.cartItems.length > 0) {
          this.cartItems.forEach((v, indx) => {
            this.productAmt += parseInt(v.totalPrice);
          });
          this.totalAmount = this.productAmt + this.shippingFee;
        }
        loader.dismiss();
      })
      .catch(err => {});
  }

  ionViewDidLoad() {
    this.authService
      .getuserdetails()
      .then((response: any) => {
        this.customerName = response.name;
      })
      .catch(err => {
        console.log("err", err);
      });
  }



And finally in this checkout.ts file we have the placeOrder method:
 

  placeOrder() {
    let loader = this.loadingCtrl.create({
      content: "Placing Order.."
    });
    loader.present();
    var user = firebase.auth().currentUser;
    if (user) {
      let orderObj = {
        customerId: user.uid,
        name: this.customerName,
        shipping: this.shippingFee,
        orderAmount: this.productAmt,
        amount: this.totalAmount,
        orders: this.cartItems
      };

      this.orderService.placeOrder(orderObj).then(() => {
        loader.dismiss();
        this.navCtrl.setRoot('HomePage');
        
      });
    } else {
      loader.dismiss();
    }
  }

The SignIn and Register Page 

 The signin and register page is required for an existing customer to login in other to complete purchase. The page will look like so:


Open the login.ts file and replace the code with the following methods:

Register.ts File

 

  register() {
    var userObj = {
      name: this.name,
      address: this.address,
      email: this.email,
      password: this.password
    };

    this.AuthService.registerUser(userObj)
      .then((response: any) => {
        if (response.success == true) {
          this.navCtrl.push('CheckoutPage');
        }
      })
      .catch(err => {
        alert(JSON.stringify(err));
      });
  }

  showLoginPage() {
    this.navCtrl.push("LoginPage");
  }

Login.ts File

  login() {
    let loader = this.loadingCtrl.create({
      content: 'Authenticating..'
    });
    loader.present();
    let loginParams = {
      email:this.email,
      password:this.password
    }

    this.authService.login(loginParams).then((res)=>{
      loader.dismiss();
      this.navCtrl.push('CheckoutPage');
    }).catch((err)=>{
      loader.dismiss();
      this.presentAlert(err.message);
    });


  }

  showRegisterPage() {
    this.navCtrl.push("RegisterPage");
  }

  presentAlert(message) {
    let alert = this.alertCtrl.create({
      title: 'Auth Error',
      subTitle: message,
      buttons: ['Close']
    });
    alert.present();
  }

Some more functionalities can be added to this application. But am going to stop here and hopefully this article has helped a lot of people to get started building an ecommerce app using ionicframework.

Happy Coding!

No comments:

Powered by Blogger.