Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Invoice Application Using Electron and ApsaraDB for MongoDB - Part 1

DZone's Guide to

Invoice Application Using Electron and ApsaraDB for MongoDB - Part 1

We'll set up an Electron project, creating a UI with Electron functionalities and go into detail as we create the functionality.

· Web Dev Zone ·
Free Resource

Deploying code to production can be filled with uncertainty. Reduce the risks, and deploy earlier and more often. Download this free guide to learn more. Brought to you in partnership with Rollbar.

Written by Sai Sarath Chandra, Alibaba Cloud Tech Share author. Tech Share is Alibaba Cloud’s incentive program to encourage the sharing of technical knowledge and best practices within the cloud community.

In our previous article, we discussed in detail about:

  • What Electron is.
  • Why you should opt for Electron.
  • Benefits and limitations of Electron.

We also briefly talked about how Electron handles a simple use case.

In this article, we will set up an Electron-based project, creating a user interface (UI) alongside Electron functionalities. We will also go into detail as we create the functionality which forms the building blocks for any Electron application.

We will be using the Boomerang UI Kit, which is built on the Bootstrap Framework. Bootstrap provides nice and customizable components, which can be used in almost any web development project. The reason I choose the Boomerang UI Kit is more of a personal choice. You can choose any other framework to work with this tutorial as we are more focusing only on the ElectronJS functionalities rather than the front-end frameworks.

Creating an Electron Template

Let’s start with the basic version of the Electron Template. This is the GitHub link of the template forked from the Official Electron Repository. If you would like to experiment, then go ahead and clone the code by visiting this link.

Below is the file structure you should see after cloning the code.

1

Let's talk briefly about what each file is responsible for.

.gitignore
Many have taken this file for granted, but the real purpose of the file is to ignore the files while committing/pushing the code to the git repository. This will make sure unnecessary files are not pushed into the repository.

LICENSE.md
This outlines the Licensing structure of the code you are releasing as an open source. Make sure you check all the licenses and pick what suits you best.

README.md

This is the front page you see when the repository is opened. The markdown is a special format of writing the documentation which is very easy with enough formatting options to make the content readable.

Index.html
The file where we should keep our presentation logic. All the UI design with HTML and CSS should go here. It might happen we maintain different files or a single HTML page for the whole application based on the UI architecture you follow. There are also a couple of changes you need to make to make sure your tag works, which we will discuss shortly.

main.js
This is the heart of the Electron application, this consists of the complete communication from the IPCMain process to the IPCRenderer process. We will see in detail how it works when we discuss the code. This file is responsible for all Inter-Process Communication.

Package.json
This file will be familiar to you if you have experience with Node.js; it's just a file with a list of dependencies for production and development. The equivalent can also be found in Java in the form of pom.xml.

Renderer.js
This is the renderer part of the Inter-Process Communication. Note that you can have multiple renderer.js files but it's not advisable to have multiple main.js files, as it very difficult to maintain and follow the chain of events.

Desktop Invoicing Application Using Electron

We are creating the Invoicing Application based on Electron. We start by creating the UI for the application

UI and UX

I chose the Boomerang UI Kit. This is created on top of the Bootstrap framework which provides an easy way to develop responsive and beautiful User Interfaces. There are so many pre-defined code snippets which can help you get started.

The whole code snippet I show you today is taken from the repo below:

https://github.com/saichandu415/Electron-Invoice-ApsaraDB-MongoDB

Clone the code, and you should find "Electron_Invoice" and "Invoice_Backend." Electron_Invoice consists of the whole front-end code we are discussing in this article.

<link href="https://fonts.googleapis.com/css?family=Nunito:400,600,700,800|Roboto:400,500,700" rel="stylesheet">
<!-- Theme CSS -->
<link type="text/css" href="./assets/css/theme.css" rel="stylesheet">
<!-- Font Awesome -->
<link href='http://fonts.googleapis.com/css?family=Grand+Hotel' rel='stylesheet' type='text/css'>

We are linking theme.css, which contains all the required CSS constructs for styling the elements of the basic Bootstrap framework. Linking CSS is straightforward.

If we navigate to the end of the </body> tag you will find several scripts. One of which is the following:

<script>
// You can also require other files to run in this process
require('./renderer.js');
</script>

Here we are injecting renderer.js. In renderer.js, you can access complete DOM and npm (Node Package Manager) modules.

<script>
if (typeof module === 'object') {
window.module = module;
module = undefined;
}
</script>
<!-- Start Script dependencies -->
<!-- Core -->
<script src="./assets/vendor/jquery/jquery.min.js"></script>
<script src="./assets/vendor/popper/popper.min.js"></script>
<script src="./assets/js/bootstrap/bootstrap.min.js"></script>
<!-- FontAwesome 5 -->
<script src="./assets/vendor/fontawesome/js/fontawesome-all.min.js" defer></script>
<!-- Page plugins -->
<script src="./assets/vendor/bootstrap-select/js/bootstrap-select.min.js"></script>
<script src="./assets/vendor/bootstrap-tagsinput/bootstrap-tagsinput.min.js"></script>
<script src="./assets/vendor/input-mask/input-mask.min.js"></script>
<script src="./assets/vendor/nouislider/js/nouislider.min.js"></script>
<script src="./assets/vendor/textarea-autosize/textarea-autosize.min.js"></script>
<!-- Theme JS -->
<script src="./assets/js/theme.js"></script>
<!-- Chart JS Plugin -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<!-- Mustache JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.js"></script>
<!-- Ending Script dependencies -->
<script>
if (window.module) module = window.module;
</script>

This is the most important piece of code you need to understand as this hinders the dependencies to integrate properly. Note that before you start adding any .js dependencies, we need to add the script above the comment "starting script dependencies." If not, modules like jQuery and other libraries will not be available.

In Electron, all the libraries should be available as modules. By enclosing the imports between the scripts of "Starting and Ending script dependencies," all are imported successfully and made available.

The imports we are using include:

  • jQuery, Popper, Bootstrap – for Boomerang UI interdependencies as the UI Kit is built on top of that.

  • Font Awesome – for fully scalable icons integrated as font.

  • Page plugins – These are used to create an additional functionality to the existing elements we are using as part of our HTML.

  • Theme – This JavaScript code is more bound with the theme.css which is also responsible for the animations, interpolations, etc.

  • ChartJS – We are using ChartJS for showing the analytical analysis in a graphical form. This library is open-source and it provides a lot of charts which are easy to customize.

  • Mustache.js – We used Mustache to create HTML dynamically at runtime with ease. This library greatly simplifies the work of generating dynamic HTML and replacing the values using a list.

Before I discuss any other code snippets, let's see how our end product will look.

2

3

4

Sales Visualization

These are the two screens we are designing now:

  • New Invoice: This is the window where we have a form to make the user create a new invoice.
  • Dashboard: Dashboard is where we see the user sales analysis, total orders, and total sales in a graphical way.

5

The above UI part is achieved using the following code:

<div class='navigationBar'>
        <ul class="nav nav-pills nav-fill flex-column flex-sm-row" id="myTab" role="tablist">
          <li class="nav-item">
            <a class="nav-link mb-sm-3 active" id="home-tab" data-toggle="tab" href="#newInvoice" role="tab" aria-controls="home" aria-selected="true">New Invoice</a>
          </li>
          <li class="nav-item">
            <a class="nav-link mb-sm-3" id="profile-tab" data-toggle="tab" href="#dashboard" role="tab" aria-controls="profile" aria-selected="false">DashBoard</a>
          </li>
        </ul>
        <div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="newInvoice" role="tabpanel" aria-labelledby="home-tab">
** Content of Home **
</div>
          <div class="tab-pane fade" id="dashboard" role="tabpanel" aria-labelledby="profile-tab">
** Content of DashBoard **
</div>

We follow the single page UI architecture wherein we will create the whole page at once in a single HTML file and we show what is needed.

In the <ul> with the id myTab we'll hold the complete list of tabs – both New Invoice and Dashboard. But don't ignore the classes applied to the HTML tags, they’re necessary; otherwise, the tabs might not have the same presentation format.

The other <div>s with tab-pane hold the content related to both New Invoice and Dashboard.

<div class="input-group-prepend">
   <span class="input-group-text">
       <i class="fas fa-user"></i>
   </span>
</div>
<input type="text" class="form-control" id="customerName" placeholder="Customer Name">

6

This is one of the component that we used in the form, the icon will be created the tag and they are available with font awesome which we added earlier.

Input

7

<table class="table">
              <thead class="thead-dark">
                <tr>
                  <th scope="col" class='centerme'>Item Details</th>
                  <th scope="col" class='centerme'>Qty</th>
                  <th scope="col" class='centerme'>Rate</th>
                  <th scope="col" class='centerme'>Amount</th>
                  <th scope="col"></th>

                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>
                    <div class="form-group">
                      <input type="text" id="itemDetails" class="form-control border-0" placeholder="Item Details">
                    </div>
                  </td>
                  <td>
                    <div class="form-group">
                      <input type="number" id="quantity" class="form-control border-0" placeholder="Quantity">
                    </div>
                  </td>
                  <td>
                    <div class="form-group">
                      <input type="number" id="rate" class="form-control border-0" placeholder="Rate">
                    </div>
                  </td>
                  <td>
                    <div class="form-group">
                      <input type="number" id="amount" class="form-control border-0" placeholder="Amount" readonly>
                    </div>
                  </td>
                  <td class=''>
                    <button type="button" onclick="addItemCard()" class="btn btn-success btn-icon-only rounded-circle">
                      <span class="btn-inner--icon">
                        <i class="fas fa-check"></i>
                      </span>
                    </button>
                  </td>
                </tr>
              </tbody>
            </table>

This particular piece of code creates the table header and set of inputs along with the button against it.

The green button creates an entry with the Item details provided, then you can see the following entry:

8

The card input with the Item Details are created with the following code:

<!-- Template here Starts -->
<script id="tutorial-template" type="text/template">
  <tr class="bg-white">
    <th scope="row">
      <div class="media align-items-center">
        <span class="avatar avatar-lg bg-pink mr-3">{{itemShortName}}</span>
        <div class="media-body">
          <h6 class="h5 font-weight-normal mb-0">{{ItemName}}</h6>
          <span class="font-weight-normal text-muted">Quantity :
            <b>{{qty}}</b>
          </span>
        </div>
      </div>
    </th>
    <td>Rate/pc : {{rate}}</td>
    <td>Amount : {{amount}}</td>
  </tr>
  <tr class="table-divider"></tr>
</script>
<!-- Template here ends -->

This template is generated dynamically and added to the below table at runtime using the below function:

function addItemCard() {
    var data = {};

    data.itemShortName = ($("#itemDetails").val()).substring(0, 2).toUpperCase();
    data.ItemName = $("#itemDetails").val();
    data.qty = $("#quantity").val();
    data.rate = $("#rate").val();
    data.amount = $("#amount").val();

    if (!itemsObj.customerName) {
      itemsObj.customerName = $("#customerName").val();
    }

    if (!itemsObj.invoiceNumber) {
      itemsObj.invoiceNumber = $("#invoiceNumber").val();
    }
    if (!itemsObj.invoiceDate) {
      itemsObj.invoiceDate = $("#invoiceDate").val();
    }
    if (!itemsObj.dueDate) {
      itemsObj.dueDate = $("#dueDate").val();
    }
    itemsObj.itemsData.push(data);
    var template = $("#tutorial-template").html();
    var html = Mustache.render(template, data);
    $("#cardsList").append(html);

  }

Upon clicking, addItemCard() will be invoked and the data is pushed intoitemsObj (which will be used later to push data to the server). It also creates the card template using the Mustache library and appends it to the table.

<table class="table table-hover table-cards align-items-center">
              <tbody id="cardsList">
                <!-- Dynamically generated template goes here -->
              </tbody>
            </table>

Reset
We have the “Reset” button which resets the complete data in the form to like a new Invoice form.

Submit
This is one more functionality where we will make an API call which takes care of inserting the data to the database.

function submitData() {
    console.log('submit Clicked');
    var itemsArr = itemsObj.itemsData;
    var totalAmount = 0;
    console.log(itemsArr);

    for (var i = 0; i < itemsArr.length; i++) {
      totalAmount = totalAmount + parseFloat(itemsArr[i].amount);
    }
    console.log(totalAmount);
    itemsObj.totalAmount = totalAmount;
    console.log(JSON.stringify(itemsObj));

    $.ajax({
      type: 'POST',
      data: JSON.stringify(itemsObj),
      contentType: 'application/json',
      url: 'http://149.129.130.26:443/data/invoice',
      success: function (data) {
        console.log('success');
        console.log(JSON.stringify(data));
        $("#modal_5").modal("show");
      }
    });
  }

This is the POST call to the above-mentioned URI, which is operating in the ECS Instance and takes care of inserting data into the MongoDB instance. We will discuss more about the backend soon.

Dashboard
The dashboard is made of the below components

9

The above component is created using the following code:

<div class="card">
                  <div class="card-header">
                    <div class="row align-items-center">
                      <div class="col-8">
                        <h4 class="heading h5 mb-0">Today Orders</h4>
                      </div>
                      <div class="col-4">
                        <div class="card-icon-actions text-right">
                          <a href="#" class="favorite" data-toggle="tooltip" data-original-title="Save as favorite">
                            <i class="fas fa-star"></i>
                          </a>
                          <a href="#" class="love active" data-toggle="tooltip" data-original-title="Love this">
                            <i class="fas fa-heart"></i>
                          </a>
                        </div>
                      </div>
                    </div>
                  </div>
                  <div class="card-body">
                    <p class="card-text" id="saleCount">Count : 0</p>
                  </div>
                  <div class="card-footer">
                    <div class="row align-items-center">
                      <div class="col-6">
                        <a href="#" class="btn btn-sm btn-primary" onclick="fetchAndLoadValues()">Refresh Now</a>
                      </div>
                      <div class="col-6 text-right">
                        <span class="text-muted" id="saleCountUpdateValue">2 hrs ago</span>
                      </div>
                    </div>
                  </div>

The above code creates the Card with the icons, header, and button along with the recent refreshed time from MongoDB.

We have also used the Chart.js for the graphical representation of the sales with the respective dates. You can see that in the script section under the tag for reference. It should be very obvious.

We will discuss the functionality we have used to fetch data and analyze it in the code:

  function fetchAndLoadValues() {
    var ajaxResult = {};
    $.ajax({
      url: "http://149.129.130.26:443/data/dashboard", success: function (result) {
        console.log(result);
        ajaxResult = result;
        dataVariable.data.labels = ajaxResult.datesArr;
        dataVariable.data.datasets[0].data = ajaxResult.salesArr;
        $('#saleValueUpdateTime').text(timeNow());
        $('#saleCountUpdateValue').text(timeNow());
        $('#saleValue').text("sale Value : $ " + (ajaxResult.salesArr)[0]);
        $('#saleCount').text("Count : " + (ajaxResult.ordersArr)[0]);
        loadLineChart();
      }
    });

The fetchAndLoadValues() function will make an AJAX (Asyncronous JavaScript and XML) call to the API on ECS instance and fetches the values and performs the below operations:

  • Updates the value of sale Value refresh time.
  • Updates the value of Total Orders Count update time.
  • The total sale Value of the current day.
  • Total order count of all the orders on that day.
  • Creating an array of total sale value and dates of the previous 5 days for the graph.

What's Next?

We will be discussing the how we created the backend services used for this application and what operations we can perform with our application. If you haven't read about the benefits of Electron, then you should definitely check out the previous article from this tutorial series.

Deploying code to production can be filled with uncertainty. Reduce the risks, and deploy earlier and more often. Download this free guide to learn more. Brought to you in partnership with Rollbar.

Topics:
electron ,cross-platform app development ,web dev ,node.js

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}