Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

We will leverage on Bootstrap in this project, so run the following command to get it and jQuery (Bootstrap relies on this) setup.

...

Navigate to the main.js in the src directory and add the following code

Code Block
languagejs
import 'bootstrap'; 
import 'bootstrap/dist/css/bootstrap.min.css';

...

Open the App.vue file in the src directory and edit to look like this:

Code Block
languagejs
<template>
  <div id="app">
    <Products />
  </div>
</template>

<script>
import Products from './components/Products.vue'

export default {
  name: 'App',
  components: {
    Products
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

...

Open the Products file in the components directory and add the following code:

Code Block
languagejs
<template>
    <div class="container">
        <div class="card">
            <div class="card-header">
                All products
            </div>
            <div class="card-body">
                pRODUCTS
            </div>
        </div>

    </div>
</template>

<script>
export default {
    name: 'Products',

    methods: {
        getAllProducts() {
            const baseUrl = process.env.VUE_APP_API_BASE_URL;

            this.axios.get(baseUrl + '/api/product').then(response => {
                console.log(response);
            })
        }
    },
    mounted() {
        this.getAllProducts();
    }
}
</script>

...

Edit the Product.vue file to look like this:

Code Block
languagejs
<template>
    <div>
        <h1>Merce's store</h1>
        <hr>
        <div class="row">
            <div class="col-sm-4" v-for="product in products" v-bind:key="product.id">
                <div class="card">
                    <div class="card-body">
                        <h5 class="card-title">{{ product.name }}</h5>
                        <p class="card-text">Selling for ₦{{Intl.NumberFormat().format(product.price)}}</p>
                        <a href="#" class="btn btn-primary" @click="addProductToCart(product)">Add to cart</a>
                    </div>
                </div>
            </div> 
        </div>
    </div>
</template>

<script>
export default {
    name: 'Products',
    data() {
        return {
            products: []
        }
    },
    methods: {
        addProductToCart() {

        },
        getAllProducts() {
            const baseUrl = process.env.VUE_APP_API_BASE_URL;

            this.axios.get(baseUrl + '/api/product').then(response => {
                this.products = response.data;
            })
        }
    },
    mounted() {
        this.getAllProducts();
    }
}
</script>

...

Add the following code to the Cart.vue file in the components directory:

Code Block
languagejs
<template>
    <div>
        <h1>Basket</h1>
        <hr>
        <table class="table">
            <thead>
                <tr>
                <th scope="col">#</th>
                <th scope="col">Item</th>
                <th scope="col">Price</th>
                <th scope="col">Quantity</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <th scope="row">1</th>
                    <td>JDL EXTREME</td>
                    <td>600000</td>
                    <td>x2</td>
                </tr>
            </tbody>
        </table>
    </div>
</template>


<script>
export default {
    name: 'Cart',
    data() {
        return {
            items: []
        }
    },
    methods: {

    },
    created() {
    }
}
</script>

...

We have implemented the products and cart view, developed in their own component. This is done for modularity. We need a way for both components to communicate such that the once the “Add to cart” button is clicked in the products view, the cart reflects the added product.

...

Update your main.js file in the src directory to look like this:

Code Block
languagejs
import Vue from 'vue'
import App from './App.vue'
import 'bootstrap'; 
import 'bootstrap/dist/css/bootstrap.min.css';
import axios from 'axios'
import VueAxios from 'vue-axios'

Vue.config.productionTip = false

Vue.use(VueAxios, axios)

export const bus = new Vue();
window.Vue = Vue;

new Vue({
  render: h => h(App),
}).$mount('#app')

...

Let us add a button to send the cart item to our backend and the functionality to load the checkout url in our browser. Update the Cart.vue to look like this.

Code Block
languagejs
<template>
    <div>
        <h1>Basket</h1>
        <hr>
        <table class="table">
            <thead>
                <tr>
                <th scope="col">#</th>
                <th scope="col">Item</th>
                <th scope="col">Price</th>
                <th scope="col">Quantity</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="(item, index) in cartItems" v-bind:key="item.id">
                    <th scope="row">{{index + 1}}</th>
                    <td>{{item.name}}</td>
                    <td>₦{{Intl.NumberFormat().format(item.price)}}</td>
                    <td>x{{item.quantity}}</td>
                </tr>
            </tbody>
        </table>
        <div class="row">
            <div class="col-sm-6">
                <button class="btn btn-primary" @click="payForCartItems" :disabled="items.length <= 0">Pay now</button>
            </div>
             <div class="col-sm-6">
                Total: ₦{{Intl.NumberFormat().format(getCartTotal())}}
            </div>
        </div>
    </div>
</template>


<script>
import { eventBus } from '../main'

export default {
    name: 'Cart',
    data() {
        return {
            items: []
        }
    },
    methods: {
        addProductToCart(product) {
            if (this.items.length > 0) {
                const productIndex = this.items.findIndex(productInCart => productInCart.id === product.id);

                if (productIndex > -1) {
                    let productFound = this.items[productIndex];

                    productFound.quantity++;
                    productFound.totalPrice = productFound.quantity * productFound.price;
                    return window.Vue.set(this.items, productIndex, product);
                }
            }
            product.quantity = 1;
            product.totalPrice = product.quantity * product.price;
            this.items.push(product);
        },
        payForCartItems() {
            const cartData = {
                totalAmount: this.getCartTotal(),
                paymentDescription: "payment for item's merce's store",
                customerName: "Fake name",
                customerEmail: "Fakeemail@fakeemail.com"
            };

            const baseUrl = process.env.VUE_APP_API_BASE_URL;

            this.axios.post(baseUrl + '/api/product/process-payment', cartData).then(response => {
                if (response.status === 200) {
                    return window.open(response.data, '_blank').focus();
                }
                return alert("Failed to receive checkout url");
            })
        },
        getCartTotal() {
            return this.items.reduce((a, b) => +a + +b.totalPrice, 0);
        }
    },
    created() {
        eventBus.$on('add-product-to-cart', this.addProductToCart);
    },
    computed: {
        cartItems() {
            return this.items;
        }
    }
}
</script>

...