Configure the Client Directory
Let’s now configure the client component. The client directory contains:
- The index.html file that contains the HTML code for the frontend application
- The main.css file that contains the CSS code
- The main.js file that contains the JavaScript code
- The client-package.json configuration file
We will be coding index.html, main.js and main.css. We will also create a new file login.html in this directory and add code in it.
Copy the code below and paste it in the respective files located in the client/ directory of your project using an IDE and save the files.
index.htmlcopy<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CRM Lead Manager</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" media="screen" href="main.css" /> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.19.1/css/mdb.min.css" rel="stylesheet"> <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"> </script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"> </script> <script src="main.js"></script> <script src="https://static.zohocdn.com/catalyst/sdk/js/2.0.0/catalystWebSDK.js"></script> <script src="/__catalyst/sdk/init.js"></script> <link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> <style> #connect { height: 260px; width: 500px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; } </style> </head> <body onload="getUserDetails()"> <br> <center> <h1>CRM Lead Manager</h1><br> </center> <div id="connect"> <center> <p>Click here to connect to Zoho CRM</p> <button onclick='navigate()'> <img src="https://www.zohowebstatic.com/sites/default/files/styles/product-home-page/public/icon-crm_blue.png" style="width: 180px;height: 130px;"> </button> </center> </div> <div style="width: 200px;float: right; margin-right: 30px;"><label for="logoutbtn" class="btn btn-success btn-block btn-outlined">Logout</label> <button id="logoutbtn" onclick="logout()" style="display: none;"></button> </div> <div id="main"> <div class="container"> <ul class="nav nav-tabs nav-justified mb-3" id="myTab" role="tablist"> <li class="nav-item"> <a class="nav-link active" id="check-tab" data-toggle="tab" href="#check" role="tab" aria-controls="check" aria-selected="true">Add a Lead</a> </li> <li class="nav-item"> <a class="nav-link" id="report-tab" data-toggle="tab" href="#report" onclick="getLeads()" role="tab" aria-controls="report" aria-selected="false">Manage Leads</a> </li> </ul><br> <div class="tab-content" id="myTabContent"> <div class="tab-pane fade show active" id="check" role="tabpanel" aria-labelledby="check-tab"> <div class="tab-pane fade show active" id="ex3-tabs-1" role="tabpanel" aria-labelledby="ex3-tab-1"> <div style="margin-left: 100px; margin-right:100px;"> <form id="leads"> <!-- 2 column grid layout with text inputs for the first and last names --> <div class="row mb-4"> <div class="col"> <div class="form-outline"> <label class="form-label" for="form6Example1">First name</label> <input type="text" id="firstName" class="form-control" /> </div> </div> <div class="col"> <div class="form-outline"> <label class="form-label" for="form6Example2">Last name</label> <input type="text" id="lastName" class="form-control" required /> </div> </div> </div> <!-- Text input --> <div class="form-outline mb-4"> <label class="form-label" for="form6Example3">Company name</label> <input type="text" id="companyName" class="form-control" /> </div> <!-- Email input --> <div class="form-outline mb-4"> <label class="form-label" for="form6Example5">Email</label> <input type="email" id="email" class="form-control" /> </div> <!-- Text input --> <div class="form-outline mb-4"> <label class="form-label" for="form6Example4">State</label> <input type="text" id="state" class="form-control" /> </div> <!-- Number input --> <div class="form-outline mb-4"> <label class="form-label" for="form6Example6">Phone</label> <input type="number" id="phone" class="form-control" /> </div> <!-- Number input --> <div class="form-outline mb-4"> <label class="form-label" for="form6Example6">Lead Source</label> <input type="text" id="leadSource" class="form-control" /> </div> <!-- Submit button --> <center><button type="submit" onclick="createLead();return false;" class="btn btn-primary btn-block mb-4" style="width: 100px;">Add Lead</button> <div id="loader" style="display: none;"> <div class="spinner-border" role="status"> <span class="sr-only">Loading...</span> </div> </div> </center> </form> </div> </div> </div> <div class="tab-pane fade" id="report" role="tabpanel" aria-labelledby="report-tab"> <center> <div id="loaders" style="display: none; padding-top: 200px;"> <div class="spinner-border" role="status"> <span class="sr-only">Loading...</span> </div> </div> </center> <p id="showData"></p> </div> </div> </div> <!-- Modal --> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="vertical-alignment-helper"> <div class="modal-dialog vertical-align-center"> <div class="modal-content"> <center> <h4 class="modal-title" id="myModalLabel"></h4> <div class="modal-body" id="message"></div> <div class="modal-footer"> <button type="button" style="background-color: #007bff;color: white;" class="btn btn-default" data-dismiss="modal">Close</button> </div> </center> </div> </div> </div> </div> <div class="modal fade" id="editForm" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="vertical-alignment-helper"> <div class="modal-dialog vertical-align-center"> <div class="modal-content"> <div style="margin-left: 80px; margin-right:80px;"> <br> <center> <h2>Edit Lead</h2> </center> <br> <form id="editLeads"> <!-- 2 column grid layout with text inputs for the first and last names --> <div class="row mb-4"> <div class="col"> <div class="form-outline"> <label class="form-label" for="form6Example1">First name</label> <input type="text" id="editfirstName" class="form-control" /> </div> </div> <div class="col"> <div class="form-outline"> <label class="form-label" for="form6Example2">Last name</label> <input type="text" id="editlastName" class="form-control" required /> </div> </div> </div> <!-- Text input --> <div class="form-outline mb-4"> <label class="form-label" for="form6Example3">Company name</label> <input type="text" id="editcompanyName" class="form-control" /> </div> <!-- Email input --> <div class="form-outline mb-4"> <label class="form-label" for="form6Example5">Email</label> <input type="email" id="editemail" class="form-control" /> </div> <!-- Text input --> <div class="form-outline mb-4"> <label class="form-label" for="form6Example4">State</label> <input type="text" id="editstate" class="form-control" /> </div> <!-- Number input --> <div class="form-outline mb-4"> <label class="form-label" for="form6Example6">Phone</label> <input type="number" id="editphone" class="form-control" /> </div> <!-- Submit button --> <center><button type="submit" id="editBtn" onclick="editLead();return false;" class="btn btn-primary btn-block mb-4" style="width: 100px;">Edit</button> <div id="loader" style="display: none;"> <div class="spinner-border" role="status"> <span class="sr-only">Loading...</span> </div> </div> </center> </form> </div> </div> </div> </div> </div> <div class="modal fade right" id="ModalDanger" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-dialog modal-notify modal-danger modal-side modal-top-right" role="document"> <!--Content--> <div class="modal-content"> <!--Header--> <div class="modal-header"> <p class="heading">Lead Deletion</p> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true" class="white-text">×</span> </button> </div> <!--Body--> <div class="modal-body"> <div class="row"> <div class="col-9"> <p>Are you sure you want to delete the Lead?</p> </div> </div> </div> <!--Footer--> <div class="modal-footer justify-content-center"> <a type="button" class="btn btn-danger" id="delete-btn" onclick="deleteLead()">Delete</a> <a type="button" class="btn btn-outline-danger waves-effect" data-dismiss="modal">Cancel</a> </div> </div> <!--/.Content--> </div> </div> </div> </body> <script> //Add Your Client ID and Redirect URL here function navigate() { window.location.href = "https://accounts.zoho.com/oauth/v2/auth?scope=ZohoCRM.modules.ALL&client_id={{YOUR_CLIENT_ID}}&response_type=code&access_type=offline&redirect_uri="+location.protocol + '//' + location.host + "/server/crm_crud/generateToken"; } </script> </html>
Note:After you copy and paste this code in your function file, ensure that you replace the value of your Client ID in line 293.
main.jscopyfunction createLead() { debugger; $("#loader").show(); var firstName = $("#firstName").val(); var lastName = $("#lastName").val(); if (lastName == "") { alert("Kindly Enter the Last Name"); $("#loader").hide(); return; } var companyName = $("#companyName").val(); var email = $("#email").val(); var state = $("#state").val(); var phone = $("#phone").val(); var leadSource = $("#leadSource").val(); $.ajax({ url: "/server/crm_crud/crmData", type: "post", contentType: "application/json", data: JSON.stringify({ "First_Name": firstName, "Last_Name": lastName, "Company": companyName, "Email": email, "State": state, "Phone": phone, "Lead_Source": leadSource, }), success: function (data) { debugger; $('#leads').trigger("reset"); $("#myModalLabel").html("
Success"); $("#message").html("Lead Created Successfully"); $("#loader").hide(); $('#myModal').modal('show'); }, error: function (error) { $('#leads').trigger("reset"); $("#myModalLabel").html("
Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function logout() { var redirectURL = "http://localhost:3000/app/signin.html"; //Add your app domain var auth = catalyst.auth; auth.signOut(redirectURL); } function getUserDetails() { $("#main").hide(); $("#connect").hide(); catalyst.auth.isUserAuthenticated().then(result => { $("#loader").show(); $.ajax({ url: "/server/crm_crud/getUserDetails", type: "get", success: function (data) { $("#loader").hide(); if (data.userId) { $("#main").show(); $("#connect").hide(); } else { $("#connect").show(); $("#main").hide(); } }, error: function (error) { $("#myModalLabel").html("
Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); }).catch(err => { document.body.innerHTML = 'You are not logged in. Please log in to continue. Redirecting you to the login page..'; setTimeout(function () { window.location.href = "login.html"; }, 3000); }); } function getLeads() { debugger; var tableContainer = document.getElementById("showData"); tableContainer.innerHTML = ""; $("#loaders").show(); $.ajax({ url: "/server/crm_crud/crmData", type: "get", success: function (data) { debugger; var reqData = getRequiredData(data.data); $("#loaders").hide(); renderTable(reqData); }, error: function (error) { $("#myModalLabel").html("
Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function showDeletePopup(leadID) { $('#ModalDanger').modal('show'); var deleteBtn = document.getElementById("delete-btn"); deleteBtn.value = leadID; } function deleteLead() { var leadID = document.getElementById('delete-btn').value; $.ajax({ url: "/server/crm_crud/crmData/" + leadID, type: "delete", success: function (data) { debugger; $('#ModalDanger').modal('toggle'); $("#myModalLabel").html("
Success"); $("#message").html("Lead Deleted Successfully"); $('#myModal').modal('show'); setTimeout(function () { location.reload(); }, 3000); }, error: function (error) { $("#myModalLabel").html("
Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function showEditPopup(leadID) { $.ajax({ url: "/server/crm_crud/crmData/" + leadID, type: "get", success: function (data) { debugger; var respData = data.data; $('#editfirstName').val(respData[0].First_Name); $('#editlastName').val(respData[0].Last_Name); $('#editcompanyName').val(respData[0].Company); $('#editemail').val(respData[0].Email); $('#editstate').val(respData[0].State); $('#editphone').val(respData[0].Phone); $('#editleadSource').val(respData[0].Lead_Source); $('#editBtn').val(respData[0].id); $('#editfirstName').html(respData[0].First_Name); $('#editlastName').html(respData[0].Last_Name); $('#editcompanyName').html(respData[0].Company); $('#editemail').html(respData[0].Email); $('#editstate').html(respData[0].State); $('#editphone').html(respData[0].Phone); $('#editleadSource').html(respData[0].Lead_Source); $('#editForm').modal('show'); }, error: function (error) { $("#myModalLabel").html("
Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function editLead() { var firstName = $("#editfirstName").val(); var lastName = $("#editlastName").val(); if (lastName == "") { alert("Kindly Enter the Last Name"); return; } var companyName = $("#editcompanyName").val(); var email = $("#editemail").val(); var state = $("#editstate").val(); var phone = $("#editphone").val(); var leadSource = $("#editleadSource").val(); var leadID = $("#editBtn").val(); $.ajax({ url: "/server/crm_crud/crmData/" + leadID, type: "put", contentType: "application/json", data: JSON.stringify({ "First_Name": firstName, "Last_Name": lastName, "Company": companyName, "Email": email, "State": state, "Phone": phone, "Lead_Source": leadSource }), success: function (data) { debugger; $('#editForm').modal('toggle'); $("#myModalLabel").html("
Success"); $("#message").html("Lead Edited Successfully"); $('#myModal').modal('show'); setTimeout(function () { location.reload(); }, 3000); }, error: function (error) { $('#leads').trigger("reset"); $("#myModalLabel").html("
Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function getRequiredData(data) { var i; var resp = []; for (i = 0; i < data.length; i++) { var gulp = { "First Name": data[i].First_Name, "Last Name": data[i].Last_Name, "Phone": data[i].Phone, "Email": data[i].Email, "Company": data[i].Company, "Edit": '<center><a href="javascript:showEditPopup("' + data[i].id + '")">✎︎</a></center>', "Delete": '<center><a href="javascript:showDeletePopup("' + data[i].id + '")">🗑︎</a></center>' } resp.push(gulp); } console.log(resp); return resp; } function renderTable(respData) { var col = []; for (var i = 0; i < respData.length; i++) { for (var key in respData[i]) { if (col.indexOf(key) === -1) { col.push(key); } } } var table = document.createElement("table"); table.id = "dataTable"; var tr = table.insertRow(-1); for (var i = 0; i < col.length; i++) { var th = document.createElement("th"); th.innerHTML = col[i]; tr.appendChild(th); } for (var i = 0; i < respData.length; i++) { tr = table.insertRow(-1); for (var j = 0; j < col.length; j++) { var tabCell = tr.insertCell(-1); tabCell.innerHTML = respData[i][col[j]]; } } var divContainer = document.getElementById("showData"); divContainer.innerHTML = ""; divContainer.appendChild(table); }main.csscopy#dataTable { font-family: Arial, Helvetica, sans-serif; border-collapse: collapse; width: 100%; } #dataTable td, #dataTable th { border: 1px solid #ddd; padding: 8px; } #dataTable tr:nth-child(even){background-color: #f2f2f2;} #dataTable tr:hover {background-color: #ddd;} #dataTable th { padding-top: 12px; padding-bottom: 12px; text-align: left; background-color: #007bff; color: white; } .vertical-alignment-helper { display: table; height: 100%; width: 100%; pointer-events: none; } .vertical-align-center { display: table-cell; vertical-align: middle; pointer-events: none; } .modal-content { width: inherit; max-width: inherit; height: inherit; margin: 0 auto; pointer-events: all; }
login.htmlcopy<html> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CRM Lead Manager</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" media="screen" href="main.css" /> <script src="main.js"></script> <link rel="stylesheet" type="text/css" media="screen" href="main.css" /> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <script src="https://js.zohostatic.com/catalystclient/1.0.0/catalystWebSDK.js"></script> <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"> </script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"> </script> <script src="https://static.zohocdn.com/catalyst/sdk/js/2.0.0/catalystWebSDK.js"></script> <script src="/__catalyst/sdk/init.js"></script> <script> catalyst.auth.signIn("login"); </script> <link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> <style> #login { height: 260px; width: 500px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; } </style> <body> <br> <center> <h1>CRM Lead Manager</h1> </center> <div id="login"></div> </body> </html>
The client directory is now configured.
Let us quickly go through the working of the function and client components of the application:
The login.html file in the client component enables Catalyst Authentication login. This does not handle the Zoho sign-in feature, only the Catalyst login.
index.html contains the code for the front-end of the client. It defines a function navigate() that enables the connection to the CRM account by passing the required authorization information such as the Client ID and the scope.
The Advanced I/O function defines the following APIs that perform various actions:
/generateToken: Obtains the Refresh Token by calling the getRefreshToken() function, and inserts it along with the userID of the current user in the Token table in the Data Store. It then redirects to the index page of the client.
/getUserDetails: Fetches the user details by calling the getUserDetails() function. If there is no record in the table, a JSON response with the userID alone is sent. If the record exists in the table, it is sent along with the userID.
/crmData: This route defines the path of all leads in the Leads module. The Node function executes the HTTP GET and POST operations to fetch all leads or create a new lead using this route respectively.
/crmData/:id: This route defines the path of a particular lead in the Leads module. The id represents the unique ID of the lead in CRM. The function executes the HTTP PUT and DELETE operations to edit or delete a lead respectively using this route.
The Advanced I/O function contains the following functions that are called by the APIs:
getRefreshToken(): Fetches the Refresh Token by passing the Client ID, Client Secret, Redirect URI and other required values as query string parameters
getAccessToken(): Fetches the Access Token by passing the Refresh Token queried from the Token table using ZCQL, and other required parameters. The Access Token is fetched each time an operation needs to be performed on the CRM module, such as adding a lead or editing a lead.
getResponse(): Passes the Access Token fetched to obtain the authorization needed to perform each action on the CRM module. This function is called with each /crmData and /crmData/:id API to authorize the request.
getUserDetails(): Fetches the record from the Token table that contains the Refresh Token, by passing the userID
main.js is the JavaScript function in the client component that parses the JSON responses obtained from the function and renders them in the index.html page. This function defines the actions for all the UI elements in the client application. For example, getLeads() obtains all leads from the function response and renders them in the client, and showEditPopup() defines the actions for editing a lead.
Last Updated 2024-03-22 17:59:45 +0530 +0530