DEV Community

Akuagwu Philemon
Akuagwu Philemon

Posted on • Edited on

Creating an Inventory desktop Application with React, Apollo (Graphql), AntD, ElectronJS and, Fauna

a display of the inventory application

Authored in connection with the Write With Fauna program.

Introduction

This Article will be a walk-through on how to get started with ElectronJS and FaunaDB. We will also be going through some other libraries like ReactJS and AntD. To fully understand this walkthrough I suggest you practice along with and use The Completed project as a Guide.

Prerequisite

This Article is targeted at Beginners to ElectronJS and Fauna, a Reader you are expected to know the following

  • React JS
  • JavaScript
  • NodeJS
  • Graphql
  • Any design Library like Bootstrap / MaterialUI

What you will Learn

  • How to Setup an Electron application from Scratch
  • How to Use React and electron
  • How to connect Your electron application to a Fauna server using Apollo GraphQL client
  • How to perform basic Get, Create and Delete actions on Fauna

ElectronJS

ElectronJS is a Javascript framework that is used that allows the development of desktop GUI applications using web technologies. It utilizes the Chromium rendering engine and the Node.js runtime.

why ElectronJS

  • Cross-Platform Support: With ElectronJs you can create GUI desktop applications for multiple operating systems, for example, Windows 10 and macOS
  • Write Code once: The same codebase can be used to create both Desktop GUI application and Web applications
  • Compiling and Building: Electrons application can work without a specific runtime being installed, this simply means that you can install and run an electron application on a device without NODEJS ( JavaScript runtime Environment) being installed on it
  • Flexibility: ElectronJS can be used with most web technology Libraries, for Example ReactJS, VueJS, etc.

In this article, I will be making use of ReactJS to create an Inventory system

Fauna

Fauna is the data API for client-serverless applications. It provides a GraphQL interface and API that supports custom business logic and is integrated with the serverless ecosystem, enabling developers to build and ship faster. It provides a fast, consistent, reliable, and secure infrastructure.

Apollo Client

Apollo Client is a state management tool for JavaScript that enables you to make GraphQL requests and manage data remotely and locally
Use it to fetch, cache, and modify application data, all while automatically updating your UI. In this article, we will use React Apollo Client to interact with Fauna GraphQL API
Check Apollo Docs for more information

AntD

Ant-D short for Ant Design is a Design Library that provides High level reusable react components. They provide components such as

  • Icons
  • Layout components
  • Buttons
  • Table component
  • Modals
  • Toasts, etc

Check Ant Design Documentation for more information

Getting Started

Setup React application using “Create React App”
Run

$ npx create-react-app invetory
Enter fullscreen mode Exit fullscreen mode

Setup Electron with react

Step 1:
To set up electron we are going to start by installing the Packages necessary for it by running

$ yarn add -D concurrently electron-builder electron wait-on electron-is-dev cross-env
Enter fullscreen mode Exit fullscreen mode
  • concurrently - Run multiple commands concurrently. Like npm run watch-js; in this case, running the react server and electron server simultaneously
  • wait-on - a package that allows processes run asynchronously; in this case “awaits” the react server before starting the electron server.
  • electron- the electron framework that we will be utilizing

Step 2:
Configure the electron by following these steps :

  1. Create a file named ‘electron.js’ in the public folder

  2. In the electron.js file copy the following code and paste it

    const electron = require('electron'); // import electron package
    const app = electron.app; // assign the electron 'app' method to the app constant
    const BrowserWindow = electron.BrowserWindow;
    const path = require('path');
    const url = require('url');
    const isDev = require('electron-is-dev');
    let mainWindow;
    function createWindow() {
      mainWindow = new BrowserWindow({ width: 1020, height: 720 });
      mainWindow.setMenuBarVisibility(false); // display menu
      mainWindow.loadURL(
        isDev
          ? 'http://localhost:3000'
          : `file://${path.join(__dirname, '../build/index.html')}`
      );
      mainWindow.on('closed', () => (mainWindow = null));
    }
    app.on('ready', createWindow);
    app.on('window-all-closed', () => {
      if (process.platform !== 'darwin') {
        app.quit();
      }
    });
    app.on('activate', () => {
      if (mainWindow === null) {
        createWindow();
      }
    });
Enter fullscreen mode Exit fullscreen mode
  1. Add the Start script to the package.json file
"electron-dev":"concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://localhost:3000 && electron .\"",
Enter fullscreen mode Exit fullscreen mode

  1. Create a /dist/builder-effective-config.yaml file

and populate the file with this configuration

    directories:
      output: dist
      buildResources: assets
    files:
      - filter:
          - build/**/*
          - build/**/*
          - node_modules/**/*
    extraMetadata:
      main: build/electron/main.js
    appId: com.example.electron-cra
    extends: react-cra
    electronVersion: 9.0.4
Enter fullscreen mode Exit fullscreen mode
  1. Direct the electron CLI to the ‘electron.js’ file by adding "main": "public/electron.js",

in the package.json file

Lastly, run

$ npm run electron-dev
Enter fullscreen mode Exit fullscreen mode

If you followed all the steps correctly, you should have your app launched successfully, if you are having troubles, simply clone the React-Electron-Stater repo

Setup Electron with AntD

As stated earlier in this Article, AntD is the design library used in this project, and setting it with our Electron application is as easy as setting AntD up with react. Follow these steps to do so
step 1:
install the following dependencies

$ yarn add antd @ant-design/icons
Enter fullscreen mode Exit fullscreen mode

Step2 :
In the src/index.js file, import AntD stylesheet by add “import 'antd/dist/antd.css';” to the top of the file I will not elaborate much on AntD since it is not the main focus of this Article. For more information visit AntD official doc

Setup Apollo

Apollo Client is a GraphQL client used for GraphQL mutations and queries. In this article, we will use it to interact with the Fauna GraphQL API. To set up Apollo with ElectronJS and ReactJS, you should follow the steps below
step 1:
Install the following dependencies

$ yarn add @apollo/client @apollo/react-hooks graphql
Enter fullscreen mode Exit fullscreen mode

Make sure the access key to your Fauna Graphql API is saved in the .env.local file.

Checkout Migrating a react project from aws appsync to fauna to get started with Creating a Fauna GraphQL API
Note:
Make use of this GraphQL Schema

    type Inventory {
      product: String! # the name of the product
      count: String # count of the product
      id: String # special Id given to a product
    }
    type Query {
      allInventories: [Inventory!]
    }
Enter fullscreen mode Exit fullscreen mode

In the .env.local file, add an entry for the generated key:
The REACT_APP_FAUNA_SECRET=***
NOTE:

  • The config file must be named .env.local and not just .env
  • React environment variable should start with “REACT_APP_”…
  • make sure that you also have a .gitignore file in your project’s root directory that contains .env.local so that your secrets won’t be added to your git repo and shared with others.
  • You have to restart the react application for changes to take place

Step 2:
Now in the src directory of your application, add a new file named client.js with the following content:

    import { ApolloClient, InMemoryCache } from "@apollo/client";

    export const client = new ApolloClient({

    uri: "https://graphql.fauna.com/graphql",

    headers: {

    authorization: `Bearer ${process.env.REACT_APP_FAUNA_SECRET}`,

    },

    cache: new InMemoryCache(),

    });
Enter fullscreen mode Exit fullscreen mode

The code above simply configures Apollo to make requests to our Fauna database. The uri option specifies the base URI of the GraphQL API, the authorization header indicates that we’re connecting to the specific database instance for the provided key that we generated earlier.

Step 3:
After that, We will replace the code in the index.js with


    import React from 'react';

    import ReactDOM from 'react-dom';

    import { ApolloProvider } from '@apollo/client';

    import './index.css';

    import App from './App';

    import { client } from './client';

    ReactDOM.render(

    <React.StrictMode>

    <ApolloProvider  client={client}>
    <App />

    <ApolloProvider \>

    <React.StrictMode \>,

    document.getElementById('root')

    );
Enter fullscreen mode Exit fullscreen mode

Get Inventory Items

Getting data from the Fauna GraphQL API is easy and it is done using the “useQuery” from apollo/react-hook.
To make a query to a GraphQL API follow these steps:

step 1:
import the following dependencies

import { useQuery, gql } from '@apollo/react-hooks';
Enter fullscreen mode Exit fullscreen mode
  • useQuery - a react gook that is used to make GraphQL queries
  • gql - The gql template literal tag can be used to concisely write a GraphQL query that is parsed into a standard GraphQL AST.

step 2: Write the query

    const listInvetoryItems = /**GRAPHQL */ gql`
        query {
          allInventories {
            data {
              count
              product
              id
              _id
            }
          }
        }
      `;
Enter fullscreen mode Exit fullscreen mode

Step 3:

     const { data: inventoryData, error, loading } = useQuery(listInvetoryItems);
Enter fullscreen mode Exit fullscreen mode

Step 4:
Updating the React UI with the data retrieved from Fauna GraphQL query

    // From List.js line 64 
    useEffect(() => {
        if (
          inventoryData &&
          inventoryData.allInventories && // validation
          inventoryData.allInventories.data // validation
        ) {
          const newData = inventoryData.allInventories.data.map((data) => ({
            ...data,
            key: data._id, // required by antD Table to manage the state of a rows on a table
          }));// mapping response 
          setData(newData);
        }
        if (error && loading === false) {
          console.log('I think we have an error');
        }
      }, [inventoryData, error, loading]);

Enter fullscreen mode Exit fullscreen mode
  • useEffect is the hook that manages the side-effects in functional components.
  • inventoryData is destructured alias of ‘data’ which is the response of the Fauna graphQL call

Add Inventory Item

To add Items to our inventory system we are going to make GraphQL mutations making use of the Apollo client useMutaion hook. To do so, follow the steps below

Step 1 :
import the following hooks at the top of the file

import { gql, useMutation } from '@apollo/react-hooks';
Enter fullscreen mode Exit fullscreen mode
  • useMutation is an apollo/react-hooks function that is used to make graphQL Mutations

Step 2:
Write and structure the GraphQl mutation.

      const addInventoryMutation = /** GraphQL mutation */ gql`
        mutation CreateInventoryItem($data: InventoryInput!) {
          createInventory(data: $data) {
            count
            id
            product
            _id
          }
        }
      `;
Enter fullscreen mode Exit fullscreen mode
  • addInventoryMutation - is a const that contains the GraphQL mutation. You can test and structure a mutation using the graphql playground

Step 3:
Call the useMutation hook, passing the graphQL mutation string and options

    const [createItem] = useMutation(addInventoryMutation, {
        onCompleted: (data) => {
          const { createInventory } = data; // destructure data
          setData((state) => {
            return [{ ...createInventory, key: createInventory._id }, ...state];
          });
        },
      });

Enter fullscreen mode Exit fullscreen mode
  • useMutation - is imported from @apollo/react-hooks and is used to execute graphql mutations
  • createItem - useMutation hook returns an array of functions and objects, the first element of the array is a function used to make mutations. The arguments passed to the mutation is the variable of the graphql mutation

Step 4:

    // List.js line 88
     const onOk = ({ product, count, id }) => {
        createItem({ variables: { data: { product, count, id } } });
        setIsOpen(false);
      };
Enter fullscreen mode Exit fullscreen mode

Explanation:
Please go through the code The Completed project as a Guide To fully understand this Step

  • onOk - is a call back function called when the form in the modal is submitted
  • createItem is the function (first element of the array) returned by the useMutation hook
  • setIsOpen - is a function used to toggle the form Modal display

Delete Inventory Items

To delete inventory Items follow the steps below
Step 1 :
import the following hooks at the top of the file

import { gql, useMutation } from '@apollo/react-hooks';
Enter fullscreen mode Exit fullscreen mode
  • useMutation is an apollo/react-hooks function that is used to make graphQL Mutations

Step 2:
Write and structure the GraphQl mutation.

     const deleteInventoryMutation = /** GraphQL delete Mutation */ gql`
        mutation DeleteInventoryItem($id: ID!) {
          deleteInventory(id: $id) {
            count
            id
            product
            _id
          }
        }
      `;

Enter fullscreen mode Exit fullscreen mode
  • deleteInventoryMutation- is a const that contains the graphql mutation. You can test and structure a mutation using the graphql playground

Step 3:
Call the useMutation hook, passing the graphQL mutation string and options

    const [deleteItem] = useMutation(deleteInventoryMutation, {
        onCompleted: (data) => {
          setData((state) => {
            return state.filter((x) => x.key !== data.deleteInventory._id);
          });
        },
      });
Enter fullscreen mode Exit fullscreen mode
  • useMutation - is imported from @apollo/react-hooks and is used to execute graphql mutations
  • deleteItem - useMutation hook returns an array of functions and objects, the first element of the array is a function used to make mutations. The arguments passed to the mutation is the variable of the graphql mutation

Step 4:

    // List.js line 96
      const onDelete = () => {
        toDel.forEach((del) => {
          deleteItem({ variables: { id: del } });
        });
      };
Enter fullscreen mode Exit fullscreen mode

Explanation:
Please go through the code The Completed project as a Guide To fully understand this Step

  • toDel - is an Array of all selected rows in a table

Conclusion

In this article, we learned how to set up Electron JS, Apollo, ReactJS, and Fauna, We also learned how to make mutations and queries using Apollo. After this walkthrough article, I am confident that you can start creating your desktop applications using ElectronJS, react, and Fauna. Contact me on Twitter for more information.

Top comments (1)

Collapse
 
sofiiasov profile image
SofiiaSov

A big thank you to the author for this insightful guide on creating an inventory desktop application with React, Apollo (GraphQL), AntD, ElectronJS, and Fauna. Your step-by-step explanation is incredibly helpful for those diving into the world of desktop application development.

In the spirit of exploring comprehensive solutions, I recently came across an article that delves into the advantages of a custom order management system. It discusses the benefits of tailoring solutions to specific needs, which could be a great read for anyone interested in optimizing their order management workflows.

Thanks again for sharing your expertise, and I look forward to more insightful content!