JavaScript frameworks and libraries have enabled developers to create optimal solutions when building web apps. Single and progressive web applications have improved features such as loading time, SEO and accessibility. Lightweight frameworks such as Vue - which is incrementally adoptable and manages state seamlessly, are go-to options for anyone who wants to create a web app without the burden of structuring your application the "right” way. In this tutorial, we'll build a car rental application which will depict a basic payment process with Vue and Rave - a payment gateway used by businesses and freelancers to receive payments online. Let's begin.
Getting started
When we are done building this application, our payment flow should be something like this:
- A user sees a car they want to rent from the list of cars available and clicks the
Book Now
button - The user gets redirected to a payment modal where they make payment (preferably via credit card)
- When payment is made, Rave sends the user a receipt but still verifies the authenticity of the transaction. If the transaction is found to be valid, a unique authentication code is shown to the user, else an error message telling the user to retry the payment is displayed.
To build this application, we'll use the following:
- Vue CLI: Vue's command line tool used for scaffolding Vue projects.
- Vuetify: A material component design framework for Vue.
- Axios: A lightweight, promise based HTTP client used for making API calls.
- MarketCheck: An API that provides access to a database of new, used and certified vehicles.
Let's begin by installing Vue CLI. Navigate to your terminal and input the following command:
npm install -g @vue/cli-service-global
# or
yarn global add @vue/cli-service-global
#create a new Vue project
vue create car-sales-app
#navigate into the newly created app
cd car-sales-app
For styling our markup, we'll install Vuetify. In your terminal, navigate to your project's folder and input the following command to install Vuetify:
vue add vuetify
#choose default when prompted
#start a development server on localhost:8080
npm run serve
On your browser, navigate to localhost:8080
to view the app:
Next, we'll install Axios. Navigate to your project's folder and input the following command:
npm install axios
After installing Axios, we need to obtain an API key from MarketCheck. To do this, head on to MarketCheck and create an account:
At this point, the main.js
file, located in the root folder of our project should look like this:
import Vue from "vue";
import App from "./App.vue";
import vuetify from "./plugins/vuetify";
Vue.config.productionTip = false;
new Vue({
vuetify,
render: h => h(App)
}).$mount("#app");
Fetching data from our API
By default, our project has a HelloWorld
component. Let's delete that component and modify our App
component to make requests to MarketCheck's API using Axios. Using Vue's mounted()
lifecycle method, Axios makes a GET
request to the API:
// App.vue
<script>
export default {
name: "app",
mounted() {
axios
.get('https://marketcheck-prod.apigee.net/v1/search?&year=2016&make=toyota&api_key=INSERT-YOUR-API-KEY-HERE&Content-Type=application/json')
.then(response => {
this.carResponse = response.data.listings;
})
.catch(error => {
console.log(error);
});
}
}
</script>
carResponse
is a data property which is responsible for handling the data received from our API and displaying it on our browser. Let's use UI components from Vuetify and Vue directives to structure our App component:
// App.vue
<template>
<div id="app">
<header>
<h2>
RENT A CAR. CALL 080-RENT-A-CAR
</h2>
</header>
<v-container grid-list-xl>
<v-layout wrap>
<v-flex xs4 v-for="car in carResponse" :key="car[0]" mb-2>
<v-card>
<v-img :src="car.media.photo_links[0]" aspect-ratio="2"></v-img>
<v-card-title primary-title>
<div>
<h3>{{ car.build.make }} {{ car.build.model }}</h3>
<div>Year: {{ car.build.year }}</div>
<div>Type: {{ car.build.vehicle_type }}</div>
<div>Mileage: {{ car.miles }} miles</div>
<div>NGN {{ car.price }} / Day</div>
</div>
</v-card-title>
<v-card-actions class="justify-center">
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-container>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "app",
data() {
return {
carResponse: [],
}
},
mounted() {
axios
.get('https://marketcheck-prod.apigee.net/v1/search?&year=2016&make=toyota&api_key=INSERT-YOUR-API-KEY-HERE&Content-Type=application/json')
.then(response => {
this.carResponse = response.data.listings;
})
.catch(error => {
console.log(error);
});
}
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: justify;
background-color: hsla(0, 0%, 75%, 0.1);
}
header {
margin-bottom: 60px;
text-align: center;
}
</style>
Here's a view of the current state of the app in our browser:
Implementing payments with Rave
For now, we are unable to receive payments for any of the displayed vehicles. Let's change that by implementing Rave's payment gateway in our app. First, we need to sign up with Rave and create a merchant account which enables us to receive payment for goods and services:
Once we are through with the sign-up process, we should see a dashboard similar to this:
On the dashboard navigate to Settings
and then the API
tab to retrieve the API keys. As this is a tutorial, switch to Test mode
on the dashboard and make payment using a test card supplied by Rave to avoid disclosing sensitive information either by displaying our real API keys or credit card numbers. Below is a screenshot of your test API keys:
In the src/components
folder, let's create a new component and name it RaveModal
. Using Vue's create()
hook, In our newly created component, we'll create an instance of Rave's inline script and append it to the DOM:
// src/components/RaveModal.vue
created() {
const script = document.createElement("script");
script.src = !this.isProduction
? "https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/flwpbf-inline.js"
: "https://api.ravepay.co/flwv3-pug/getpaidx/api/flwpbf-inline.js";
document.getElementsByTagName("head")[0].appendChild(script);
}
Using Vue's method property, we'll embed a payment modal in our component via Rave's getPaidSetup
function:
// src/components/RaveModal.vue
methods: {
payWithRave() {
window.getpaidSetup({
customer_email: this.email,
amount: this.amount,
txref: this.reference,
PBFPubKey: this.raveKey,
onclose: () => this.close(),
callback: response => this.callback(response),
currency: this.currency,
country: this.country,
custom_title: this.custom_title,
custom_logo: this.custom_logo,
payment_method: this.payment_method,
});
}
}
Our next step will be to specify what each value in getPaidSetup
should be. We'll do this by using Vue prop types:
// src/components/RaveModal.vue
props: {
isProduction: {
type: Boolean,
required: false,
default: false //set to true if you are going live
},
email: {
type: String,
required: true
},
amount: {
type: Number,
required: true
},
raveKey: {
type: String,
required: true
},
callback: {
type: Function,
required: true,
default: response => {}
},
close: {
type: Function,
required: true,
default: () => {}
},
currency: {
type: String,
default: "NGN"
},
country: {
type: String,
default: "NG"
},
custom_title: {
type: String,
default: ""
},
custom_logo: {
type: String,
default: ""
},
payment_method: {
type: String,
default: ""
}
}
The template
in our RaveModal
component won't hold much, just a button that activates the payment modal when clicked:
// src/components/RaveModal.vue
<template>
<div class="rave">
<button class="button" @click="payWithRave">Book Now</button>
</div>
</template>
Finally, we'll import RaveModal
into our App
component and specify all the values of paywithRave()
:
// src/App.vue
<script>
import Rave from "./components/RaveModal.vue";
export default {
name: "app",
components: {
Rave
},
data() {
return {
carResponse: [],
isProduction: false,
raveKey: raveKey,
email: "ugwuraphael@gmail.com",
amount: "",
currency: "NGN",
country: "NG",
custom: {
title: "Car Shop",
logo: carLogo
},
paymentMethod: ""
};
}
}
</script>
To include the payment button on our app, embed it in our template:
// src/App.vue
<template>
<v-card-actions class="justify-center">
<rave
:isProduction="isProduction"
:email="email"
:amount="car.price"
:reference="reference"
:rave-key="raveKey"
:callback="callback"
:close="close"
:currency="currency"
:country="country"
:custom_title="custom.title"
:custom_logo="custom.logo"
:payment_method="paymentMethod"
/>
</v-card-actions>
</template
Finally, let's protect our API keys by storing them in a .env
file. In the root folder of your project, create a .env
file and store both MarketCheck and Rave APIs:
// .env
VUE_APP_CAR_API_KEY='YOUR MARKETCHECK API HERE'
VUE_APP_RAVE_TEST_KEY='YOUR RAVE API KEY HERE'
When you are done, save the .env
file and refer to the stored values in App
like this:
// src/App.vue
<script>
const carKey = process.env.VUE_APP_CAR_API_KEY;
const raveKey = process.env.VUE_APP_RAVE_TEST_KEY;
</script>
Restart the development server on your terminal, navigate to your browser and try to make a payment for one of the vehicles:
Upon payment, Rave emails the customer a receipt:
Handling payment authentication
Although we can confirm that a customer made payment by checking our Rave dashboard for details of the transaction, it's still important to perform an authentication check for each transaction to detect issues such as reversed or fraudulent transactions. To achieve this, we'll define the callback
property in Rave's getPaidSetup
function to check for the authenticity of every transaction and return its transaction ID to the customer:
<script>
import Rave from "./components/RaveModal.vue";
export default {
name: "app",
components: {
Rave
}
methods: {
callback: function(response) {
if (
response.data.tx.status == "successful" &&
response.data.tx.chargeResponseCode === "00"
) {
if (response.data.tx.fraud_status === "ok") {
alert(
`Authenticate your payment via our mobile app with this code: ${response.data.tx.txRef}`
);
}
} else {
alert("Your payment could not be processed. Please try again later");
}
}
}
</script>
Now a customer can pay for an item and get an identifier such as an authentication code as an additional layer of authenticity:
Summary
Optimizing performance when building web apps is only going to get more important. Javascript developers have a lot of frameworks and tools to choose from and Vue is an awesome option. As for implementing payment options seamlessly, Rave gets the job done. To check out the source code of this application, head on to GitHub.
Top comments (0)