In this tutorial, learn how to build a realtime payment dashboard using Stripe, Pusher, Vue.js and Node.js.
In this article, we are going to be looking at how to accept payments from a user using Stripe and displaying sales on an admin dashboard in realtime using using Pusher
Stripe is used to handle user payments and Pusher adds realtime functionality to our application.
Before you begin, you need Node and Node Package Manager( npm ) installed on your machine. To verify your installation, please run the following commands on your terminal
1npm -v 2 node -v
If you get version numbers as your response, then it means that you already have them installed and you are good to go.
Stripe is a platform that helps process online payment. We will use this to process payments in our store.
To set up a Stripe account, head over here and then fill out the form.
Once this step is completed, you will be redirected to your dashboard:
Note your STRIPE_PUBLISHABLE_KEY
and STRIPE_SECRET_KEY
. We are going to use them later on as we build our application
Pusher allows you to incorporate realtime functionality into your applications. To get started with Pusher, head over here.
Once you’re signed in, you will be redirected to your dashboard. You then need to create a new app.
After your new app is created, you need to note your PUSHER_APP_ID
, PUSHER_API_KEY
, PUSHER_API_SECRET
, PUSHER_API_CLUSTER
.
Once you have these details, you are ready to begin building your app.
Note : All source code is available here
To handle your API calls to Stripe and Pusher, we will use an Express server.
We need some node modules that are essential for our application to work:
Make a new directory and change directory into it:
1mkdir realtime-dashboard && cd realtime-dashboard
Then initialize a node project and install the node modules:
1# Initialze 2 npm init -y 3 # Install 4 npm install cors express ejs body-parser connect-multiparty pusher stripe --save
You have now installed all the modules necessary for you to build the project.
Now we need to create a file that will contain the instructions needed for our server to work
In your realtime-dashboard
directory:
1touch server.js
This is the start up file that will be referenced when your server is running
In your server.js file, you need to:
1const cors = require('cors') 2 const Pusher = require('pusher') 3 const express = require('express') 4 const bodyParser = require('body-parser') 5 const multipart = require('connect-multiparty') 6 const stripe = require('stripe')('STRIPE_API_KEY') 7 [...]
Once you have imported your node modules, you can then use them freely all through your script.
Now we create our express app by adding the following to the server.js
:
1[...] 2 const app = express() 3 [...]
We load the middleware in our server.js
by adding the following:
1... 2 app.use(cors()); 3 app.set('view engine', 'ejs'); 4 app.use(bodyParser.json()); 5 app.use(bodyParser.urlencoded({ extended: false})); 6 const multipartMiddleware = multipart(); 7 ...
Here, we set our app to use cors
and set the view engine to ejs
. We also instructed the app the parse the requests in JSON format.
We need to create our Pusher client to enable us to trigger events from our app to a specific channel. Our admin dashboard will also be listening for events on the same channel (more details on this as we progress).
We create the client by adding this to our file:
1[...] 2 const pusher = new Pusher({ 3 appId: 'PUSHERE_APP_ID', 4 key: 'PUSHER_API_KEY', 5 secret: 'PUSHER_API_SECRET', 6 cluster: 'PUSHER_APP_CLUSTER', 7 encrypted: true 8 }); 9 [...]
Once this is done, we have successfully created our Pusher client.
We need to decide what the user sees when visiting different parts of our app. Since this is a simple application, we only need two routes for the user facing side:
Earlier on, we set our view engine
to ejs
and we will use this here:
1[...] 2 app.get('/', function(req, res){ 3 res.render('index'); 4 }); 5 6 app.post('/gen-payment', multipartMiddleware, function(req, res){ 7 let amount = 500; 8 stripe.customers.create({ 9 email: req.body.stripeEmail, 10 source: req.body.stripeToken 11 }) 12 .then(customer => 13 stripe.charges.create({ 14 amount, 15 description: 'One camera bought from shop', 16 currency: "usd", 17 customer: customer.id 18 }) 19 ) 20 .then(charge => { 21 pusher.trigger('sales', 'payment-completed', { 22 "time" : new Date().toDateString(), 23 "value" : `\$${charge.amount/100}`, 24 "message" : "payment complete...duh!", 25 "description" : charge.description 26 }); 27 console.log( charge ); 28 res.render("charge"); 29 }); 30 }); 31 [...]
Let’s shed more light on the gen-payment
route. We accept the stripeEmail
and the stripeToken
which would be passed as part of the body in the post request to the route. We then create a new customer
using the stripeEmail
and the stripeToken
. The create
function returns a promise
and so once the customer is created, we initiate a new charge
for the customer. If this charge is successful, i.e we are able to completely charge the customer, then we trigger a payment-completed
event to the sales
channel.
You need to choose a port you want your app to run on. You do this by adding this following to your server.js
file:
1[...] 2 app.listen('3120') 3 [...]
At this point the backend server is all set up. Now we need to go to the views to see how data is passed to the server.
Create a views
directory. In the views directory create your index.ejs
and charge.ejs
:
1mkdir views && cd views 2 touch index.ejs charge.ejs
In our index.ejs
we need to accept user payment. To make it more secure when handling card information, Stripe has an embedded payment form called Checkout which we will use to collect user’s card data securely. The following is a truncated version of the form that sends data to our server. You can see the complete code on github.
1<form method="POST" action="http://localhost:3120/gen-payment" enctype="multipart/form-data"/> 2 <script 3 src="https://checkout.stripe.com/checkout.js" class="stripe-button" 4 data-key="PUSBLISHABLE_API_KEY" 5 data-amount="500" 6 data-name="Pay OG" 7 data-description="Send money to OG" 8 data-image="https://stripe.com/img/documentation/checkout/marketplace.png" 9 data-locale="auto"> 10 </script> 11 </form>
We submit the form to the /gen-payment
route on our server. We include the checkout.js
script and the following :
API_KEY
gotten from your dashboardOnce this is sent to the server and the request is completed successfully, we render the charge.ejs
view to the user telling the use that their payment is complete:
1<!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Realtime Payment Dashboard</title> 8 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous"> 9 <link rel="stylesheet" href="https://codepen.io/drehimself/pen/VvYLmV.css"> 10 </head> 11 <body> 12 <nav> 13 <div class="container"> 14 <ul class="navbar-left"> 15 <li><a href="#">Home</a></li> 16 <li><a href="#about">About</a></li> 17 </ul> 18 19 <ul class="navbar-right"> 20 <li><a href="#" id="cart"><i class="fa fa-shopping-cart"></i> Cart <span class="badge">0</span></a></li> 21 </ul> 22 </div> 23 </nav> 24 25 <script> 26 alert("Payment Complete"); 27 </script> 28 <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script> 29 </body> 30 </html>
We want our admin dashboard to show completed payments as they are made without having to refresh the page. To do this, we are going to make use of Vue.js and Pusher.
Before we begin, we need to install the vue-cli
by running the following command:
1npm install -g vue-cli
This will install it globally on our local machine. To confirm your installation of the vue-cli
you can run:
1vue --version
If you get the version number as a result then you’re all set!
To create the admin
server, run the following command in the realtime-dashboard
directory:
1vue init webpack admin
This will ask you a few questions on project name, description, author, etc. then it will create a new Vue project for us with some boilerplate already set up.
We need to install pusher-js
module that allows us to use pusher with our vue frontend. To do this, change directory into the admin directory and run the following command:
1npm install -S pusher-js
Now we want to create our dashboard
component:
1cd admin/src/components 2 touch Dashboard.vue
In the Dashboard.vue
, we need to import the pusher.js
module:
1<script> 2 import Pusher from 'pusher-js' 3 [...]
We then create some mock payments to populate the dashboard:
1[...] 2 const MOCK_PAYMENTS = [ 3 {time : '12th Dec, 2017', description: "Shoes", value : "$5"}, 4 {time : '12th Dec, 2017', description: "Maga don pay", value : "$12"} 5 ] 6 [...]
Now we describe our component itself:
1[...] 2 export default { 3 name: 'Dashboard', 4 data () { 5 return { 6 payments : MOCK_PAYMENTS 7 } 8 }, 9 created () { 10 this.subscribe(); 11 }, 12 methods: { 13 subscribe () { 14 let pusher = new Pusher('PUSHER_API_KEY', { 15 cluster: 'PUSHER_CLUSTER', 16 encrypted: true 17 }); 18 pusher.subscribe('sales'); 19 pusher.bind('payment-completed', data => { 20 this.payments.unshift(data); 21 }); 22 } 23 } 24 } 25 </script> 26 [...]
In the subscribe
method above, we subscribe to the sales
channel and then listen for the payment-completed
event. When a new payment-completed
event is broadcast from the backend server on the sales
, our frontend server picks it up and the adds it to the payments
array of the component.
The Dashboard.vue
also has a template which looks like this:
1[...] 2 <template> 3 <div class="container-fluid"> 4 <table class="table table-striped"> 5 <thead> 6 <tr> 7 <td>Time</td> 8 <td>Value</td> 9 <td>Description</td> 10 </tr> 11 </thead> 12 13 <tbody> 14 <tr v-for="payment in payments"> 15 <td>{{ payment.time }}</td> 16 <td>{{ payment.value }}</td> 17 <td>{{ payment.description }}</td> 18 </tr> 19 </tbody> 20 </table> 21 </div> 22 </template> 23 [...]
And some scoped css styling:
1<style scoped> 2 h1, h2 { 3 font-weight: normal; 4 } 5 ul { 6 list-style-type: none; 7 padding: 0; 8 } 9 li { 10 display: inline-block; 11 margin: 0 10px; 12 } 13 a { 14 color: #42b983; 15 } 16 .table{ 17 background-color : white; 18 } 19 </style>
Now that our dashboard component is ready, we need to import it in our App.vue
so that I would be picked up when the view is being compiled
1[...] 2 import Dashboard from './components/Dashboard' 3 export default { 4 name: 'app', 5 components: { 6 Dashboard 7 } 8 } 9 [...]
Once this is done, you should be ready to run your frontend server. You can can do this using the command:
1npm run dev
Now you can run the Dashboard
side-by-side with the Store
and then see as purchases are being made in realtime:
We have seen how to build a realtime payment dashboard using Pusher, Stripe and some Vue.js. You can view the full source code on github. There are many more use cases where realtime functionality will give you an edge. A big advantage is that you get to obtain realtime insights as to how users interact with your application.