Let’s Create a Daily Report App [Part 1: Screen Explanation and Authentication]

Athina Hadjichristodoulou
The Web Tub
Published in
9 min readJul 4, 2023

If you’re considering using Monaca to develop an application, you might find it challenging to come up with ideas when the time comes. Additionally, if you’re planning to build a complex app from scratch, it can be overwhelming to know where to begin.

That’s why in this article we will guide you through the process of developing a simple app. As a first step, we encourage you to take on the challenge.

In this article, we will develop a daily report app using NCMB (NIFCLOUD mobile backend). This article is divided into two parts. The first half is an overview of the app and an explanation of the authentication process.

Technologies and Libraries Used

The following technologies and libraries are used in this application:

  • Framework7 v8
  • NIFCLOUD mobile backend
  • dayjs (javascript library for handling dates)

To make the process of development more easy, we will use a minimal template for Framework7 in Monaca.

Screens and Permissions

Entry Screen

This is the screen where the user enters the daily report. It is the first screen that appears once the application is opened. The input fields on this screen are as follows:

  • Date: The date of the report
  • Task: Description of the work performed
  • Category: Category of the work
  • Time: Duration of the work

On this screen, the user’s login status is checked. If the user is not logged in, the screen will transition to the authentication screen.

New Entry screen

Authentication Screen

The authentication screen combines user login and new user registration into a single screen. The following fields are entered here:

  • Display Name
  • User ID
  • Password

Authentication is performed using the User ID and Password. The Display Name is used purely for the purpose of displaying tasks in a readable format.

Login/ Sign Up screen

Daily Report List Screen

This is the screen where the user can view the entered reports for the day. Regular users can view their own reports and other’s but without any indication on who submitted them. However the administrator users have the ability to view reports with the names of the users as well.

The display for regular users is as follows:

Daily Reports screen

Permissions for Report Data

Named report data can be accessed by the individual user and administrator users only. Additionally, only the individual user has the ability to delete their own data.

User Data Permissions

User data can be viewed by anyone. However, only the user can update or delete their data.

Libraries Installation

Get NIFCLOUD mobile backend key

By registering or logging in to NIFCLOUD mobile backend, you can create an app and obtain the following two keys:

  • Application Key
  • Client Key

Library Installation

Now, we can start with the development of the app. For this project, we are using the Framework7 template. We have chosen a plain JavaScript template without using any external frameworks (such as Vue or React).

Create a new project in Monaca

As external libraries, we will add ncmb and dayjs. Both of them are JavaScript libraries, so please use the “Add and remove JS/CSS components” under “Configure” in Monaca Cloud to download them. We can also use dayjs from a CDN.

Don’t forget to load the file `ncmb.min.js` as script in the index.html file.

 <!-- Ncmb script -->
<script src="components/ncmb/ncmb.min.js"></script>
<!-- Dayjs script -->
<script src="https://cdn.jsdelivr.net/npm/dayjs@1/dayjs.min.js"></script>
<script>dayjs().format()</script>

Coding Time

Initialization of NCMB

Create a file under www/js/ named app.js and initialize the NIFCLOUD mobile backend as follows. Include the application key and client key you acquired during the process “Get NIFCLOUD mobile backend key”.

var ncmb;
document.addEventListener('DOMContentLoaded', e => {
const applicationKey = '...';
const clientKey = '...';
ncmb = new NCMB(applicationKey, clientKey);
}

Introduction of index.html

In the www/index.html file, which is the initial file loaded in the Monaca app, we create a tab bar using Framework7. The files that are loaded are entry.html, the screen for inputting daily reports and browse.html the screen for viewing them.

  <!-- Views/Tabs container -->
<div class="views tabs safe-areas">
<!-- Tabbar for switching views-tabs -->
<div class="toolbar toolbar-bottom tabbar-labels">
<div class="toolbar-inner">
<a href="#view-entry" class="tab-link tab-link-active">
<i class="icon f7-icons if-not-md">house_fill</i>
<i class="icon material-icons if-md">home</i>
<span class="tabbar-label">New Entry</span>
</a>
<a href="#view-browse" class="tab-link" id="browseTab">
<i class="icon f7-icons if-not-md">square_list_fill</i>
<i class="icon material-icons if-md">view_list</i>
<span class="tabbar-label">Browse</span>
</a>
</div>
</div>

<!-- Your main view/tab, should have "view-main" class. It also has "tab-active" class -->
<!-- Entry View -->
<div id="view-entry" class="view view-main view-init tab tab-active" data-name="new_entry" data-url="/new_entry/">
<!-- New entry page will be loaded here dynamically from /catalog/ route -->
</div>

<!-- Browse View -->
<div id="view-browse" class="view view-init tab" data-name="browse" data-url="/browse/">
<!-- Browse page will be loaded here dynamically from /settings/ route -->
</div>
</div>

Input Screen Implementation

Here is an example of the HTML for the input screen, `entry.html`, which primarily displays the input fields for the daily report and contains the `#reports` element to display the entered content.

<div class="page" data-name="new_entry">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner sliding">
<div class="title">Daily Report Entry</div>
</div>
</div>
<div class="page-content">
<div class="block">
<div class="list list-strong-ios list-dividers-ios inset-ios">
<ul>
<li class="item-content item-input">
<div class="item-inner">
<div class="item-title item-label">Date</div>
<div class="item-input-wrap">
<input id="date" type="date" value="2023-06-01" placeholder="Please choose...">
</div>
</div>
</li>
<li class="item-content item-input">
<div class="item-inner">
<div class="item-title item-label">Task</div>
<div class="item-input-wrap">
<input id="description" type="text" placeholder="Description of work">
<span class="input-clear-button"></span>
</div>
</div>
</li>
<li class="item-content item-input">
<div class="item-inner">
<div class="item-title item-label">Time</div>
<div class="item-input-wrap">
<div class="range-slider range-slider-init" data-label="true">
<input id="time" type="range" value="8" min="0" max="10" step="1">
</div>
</div>
</div>
</li>
<li>
<div class="item-media">
<i class="icon demo-list-icon"></i>
</div>
<a class="item-link smart-select smart-select-init" data-open-in="popover">
<select id="category" name="category">
<option value="option" selected>Option</option>
</select>
<div class="item-content">
<div class="item-inner">
<div class="item-title">Category of Work</div>
</div>
</div>
</a>
</li>
</ul>
</div>
<button id="addItem" class="button button-large button-raised button-fill margin-top" style="width: 50%; margin: auto;">Send Report</button>
</div>
<hr class="margin-horizontal" />
<div class="block">
<div class="block-title text-align-center" style="font-size: 20px; color: black; height: 20px;">Registered Items</div>
<div class="list list-strong list-outline list-dividers-ios simple-list">
<ul id="reports"></ul>
</div>
</div>
</div>
</div>

About JavaScript

In JavaScript, we check whether the user is logged in when the screen is first displayed. This logic is implemented within the document.addEventListener(‘DOMContentLoaded’, e => {} function, which is called when the input screen is displayed.

document.addEventListener('DOMContentLoaded', e => {
//Check if the user is logged in
checkAuth();
}
var loginPopup;
//Redirect the user to the appropriate screen according to their login status
async function checkAuth() {
const loggedIn = await loginCheck.bind(this)();
if (loggedIn) {
console.log("logged in")
} else {
//If the user is not logged in, open the login-signup popup
console.log('not logged in')
loginPopup = app.popup.create({
el: "#loginScreen"
});
loginPopup.open();
}
}

To check the login status, we will utilize the user management feature of the NIFCLOUD mobile backend. First, we use ncmb.User.getCurrentUser() to retrieve information about the currently logged-in user. If this returns empty, it means the user is not logged in, and we will open the login popup.

//Check the login status of the user
async function loginCheck() {
const user = ncmb.User.getCurrentUser();
if (!user) {
// User is not logged in
return false;
}
try {
// Validate the session
await ncmb.DataStore('Test').fetch();
return true;
} catch (e) {
// If the session is invalid, an error will occur.
ncmb.sessionToken = null;
return false;
}
}

Even if we can retrieve user information, we cannot be sure if the session is still valid. To check the session’s validity, we can make a request to an arbitrary class (in this case, let’s use the Test class, which doesn’t need to pre-exist). If this request fails, it means the session is invalid (expired or other issues). In such cases we open once again the login popup.

Login Popup Implementation

Here is the implementation of the login.html popup, which is displayed when the user is not logged in. The HTML code is part of the index.html file and it is as follows. The users can enter their User ID, Password, and Display Name.

<!-- Login Popup -->
<div class="popup login-popup" id="loginScreen">
<div class="page login-screen-page">
<div class="page-content login-screen-content">
<div class="login-screen-title">Login / Sign Up</div>
<form>
<div class="list">
<ul>
<li class="item-content item-input">
<div class="item-inner">
<div class="item-title item-label">Display Name</div>
<div class="item-input-wrap">
<input type="text" name="display_name" id="displayName" placeholder="Your display name" />
<span class="input-clear-button"></span>
</div>
</div>
</li>
<li class="item-content item-input">
<div class="item-inner">
<div class="item-title item-label">Username</div>
<div class="item-input-wrap">
<input type="text" name="username" id="username" placeholder="Your username" />
<span class="input-clear-button"></span>
</div>
</div>
</li>
<li class="item-content item-input">
<div class="item-inner">
<div class="item-title item-label">Password</div>
<div class="item-input-wrap">
<input type="password" name="password" id="password" placeholder="Your password" />
<span class="input-clear-button"></span>
</div>
</div>
</li>
</ul>
</div>
<div class="list inset">
<ul>
<li><a class="list-button" id="loginBtn">Log In / Sign Up</a></li>
</ul>
</div>
</form>
</div>
</div>
</div>

The authentication process is triggered when the login button (`#login`) is pressed. This process should be implemented when the whole DOM Content had been loaded.

document.addEventListener('DOMContentLoaded', e => {
//Add login-signup button click event listener
document.querySelector("#loginBtn").onclick = () => login.bind(this)();
}

Let’s explain the actual `login` function. First, we execute the user registration process `registerUser`. If the user is already registered, this process will result in a user ID duplication error. Therefore, we use a `try/catch` block to continue the execution even if an error occurs.

//Perform authentication process
async function login() {
const userName = document.querySelector('#username').value;
const password = document.querySelector('#password').value;
const displayName = document.querySelector('#displayName').value;
//If these credentials have already been registered, the function will throw an error
try {
var user = new ncmb.User();
user.set("userName", userName)
.set("password", password)
.set("displayName", displayName)
await user.signUpByAccount();
} catch (e) {
console.log(e);
}
try {
//Login process
await ncmb.User.login(userName, password);
//If the login is a success we close the popup
loginPopup.close();
} catch (e) {
app.dialog.alert('Login failed. Please check your username and password.')
return false;
}
}

Regardless of the success or failure of user registration, we proceed to the user login process loginUser. In the case of the initial registration process, user registration and login are performed with the same user ID and password, so it should not fail. However, if the password is incorrect, it will result in an error. In this case, we notify the user of the error using an alert.

If the login is successful, we close the login popup.

NIFCLOUD Mobile Backend Management Screen

Lastly, in the management screen of NIFCLOUD mobile backend, we will create a management group. In the user management section of the management screen, we will create a role. For clarity, we will name it “admin”.

Furthermore, we will add an “admin” field for that user and set its value to true.

We can add members to view this admin group, or add them to the group using the objectId of an existing member. If someone is in this admin group, they will be able to see other users’ named data as well.

Summary

With the steps we have covered so far, the user registration (or login) process in the daily report app is complete. Once you get familiar with it, you will be able to implement authentication for other applications too. In the next part, we will continue developing the app and the functionalities of report submission and viewing.

You can find the code for this project in this GitHub repository.

--

--