--- title: "Configure the client" url: https://docs.catalyst.zoho.com/en/tutorials/dialer-app/nodejs/configure-client/ description: "Build a dialer application using Catalyst Advanced I/O Functions,Catalyst CloudScale DataStore and integration with Twilio’s Voice API that establishes an outbound call connection between your sales team and customers." last_updated: 2025-11-19T15:07:41Z service: All Services type: tutorial related_links: - name: "Client Directory Structure" url: /en/cli/v1/project-directory-structure/introduction - name: "Web Client Hosting" url: /en/cloud-scale/help/web-client-hosting/introduction --- # Configure the Client Next, let's configure the client component. The [client directory](https://docs.catalyst.zoho.com/en/cli/v1/project-directory-structure/client-directory/)contains: * The `index.html` file that contains the HTML code for the front-end application. * The `main.css` file that contains the CSS code for the front-end application. * The `main.js` file that contains the JavaScript code. * The `client-package.json` configuration file. We will be coding `index.html`, `main.css`, and `main.js`. > **Note : ** Please go through the code given in this section to make sure you fully understand it. Copy the code snippets given below and paste it in `index.html`, `main.css`, and `main.js` files respectively located in `client` directory using an IDE, then save the file. **index.html** ```xml <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Catalyst Dialer App</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> <script type="text/javascript" src="https://code.jquery.com/jquery-3.4.1.min.js"> </script> <script type="text/javascript" src="//media.twiliocdn.com/sdk/js/client/v1.3/twilio.min.js"> </script> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <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> <link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> </head> <body onload="logButton()"> <center> <h1 class="display-4">Catalyst Dialer App ☏</h1><br><br> </center> <div style="width: 200px;float: right; margin-right: 50px;"><label for="switchbutton" id="btntext" class="btn btn-primary btn-block btn-outlined"></label> <button id="switchbutton" style="display: none;"></button> </div> <center> <div id="Dialer"> <br><br><br> <br><br> <div class="form-outline"> <label for="phoneNumber">Customer Phone Number   </label> <input type="text" placeholder="(+91/Country Code)<112233445566>" name="phoneNumber" size="35" id="phoneNumber"> <br><br><br> <label for="salesNumber">Your Sales Phone Number   </label> <input type="text" placeholder="(+91/Country Code)<8899773366>" name="salesNumber" size="35" id="salesNumber"> <br> </div> <br><br> <button type="submit" id='call-customer-button' class="btn btn-success" onclick="getFormDetails();return false;">Initiate Call</button> <br><br> <h2> <p class="info" id='call-status'></p> </h2> </div> </center> <div id="CallLogs" style="display: none;"> <h1 class="display-6">Call Logs : </h1><br><br> <p id="featData"></p> <div id="loader" style="display: none;"> <div class="spinner-border" role="status"> <span class="sr-only">Loading...</span> </div> </div> </div> </body> </html> ``` **main.css** ```css body { padding: 30px; } #loader { width: 100px; height: 100px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; } #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: rgb(76, 175, 170); color: white; } ``` **main.js** ```javascript //To fetch phone numbers from the client,validate and make an outbound call function getFormDetails() { let data = { phoneNumber: $('#phoneNumber').val(), salesNumber: $('#salesNumber').val() }; if (!validateData(data)) { return false; } $.ajax({ url: "/server/dialer/makeCall", method: "post", dataType: 'json', data: { phoneNumber: data.phoneNumber, salesNumber: data.salesNumber } }).done(function (data) { alert("Call Initiated. You can check the details in Call Logs once the Call is completed"); console.log(data); }).fail(function (error) { alert(JSON.stringify(error)); }); } //To render the call log webpage function logButton() { document.getElementById("btntext").innerHTML = "View Call Logs"; document.getElementById('switchbutton').setAttribute('onclick', 'showCallLogs()'); } //To show the call logs tab in the application function showCallLogs() { document.getElementById("btntext").innerHTML = "View Dialer"; $("#Dialer").hide(); $("#CallLogs").show(); document.getElementById('switchbutton').setAttribute('onclick', 'showDialer()'); loadLog(); } //To show the dialer tab in the application function showDialer() { document.getElementById("btntext").innerHTML = "View Call Logs"; $("#Dialer").show(); $("#CallLogs").hide(); document.getElementById('switchbutton').setAttribute('onclick', 'showCallLogs()'); } //To validate the sales contact number and customer mobile number entered by the user function validateData(data) { var regex = "[+][0-9]+$"; if (data.phoneNumber.length === 0) { alert('Customer Phone number cannot be empty'); return false; } if (!data.phoneNumber.startsWith('+')) { alert('Customer Phone number must start with country code'); return false; } if (data.salesNumber.length === 0) { alert('Sales Phone number cannot be empty'); return false; } if (!data.salesNumber.startsWith('+')) { alert('Sales Phone number must start with country code'); return false; } if (!data.phoneNumber.match(regex)) { alert('Enter a valid customer number'); return false; } if (!data.salesNumber.match(regex)) { alert('Enter a valid sales number'); return false; } return true; } //To render the table data in the client end function renderTable(respData) { console.log("respData"); console.log(respData); debugger; 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.classList.add("ca-table-view"); table.setAttribute('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]]; } } debugger; var divContainer = document.getElementById("featData"); divContainer.innerHTML = ""; divContainer.appendChild(table); } //To store the call log data in appropriate columns function getRequiredData(data) { var i; var resp = []; for (i = 0; i < data.length; i++) { var gulp = { "From Number": data[i].fromNumber, "To Number": data[i].toNumber, "Call Duration": data[i].callDuration, "Call Status": data[i].callStatus, "Time Of Call": data[i].timeOfCall, "Called Country": data[i].calledCountry } resp.push(gulp); } console.log(resp); return resp; } //To fetch call logs by calling the /getLogs route and render the log data in the client function loadLog() { $("#loader").show(); $.ajax({ url: "/server/dialer/getLogs", method: "get" }).done(function (data) { $("#loader").hide(); var arr = []; for (i = 0; i < data.length; i++) { arr.push(data[i].CallLog); } var data = getRequiredData(arr); renderTable(data); }).fail(function (error) { alert(JSON.stringify(error)); }); } ``` The client directory is now configured. Let us quickly go through the working of the Advanced I/O function of the application: 1. **`validateData()` - Both the sales team's contact number and the customers number are validated in this function.The logic is defined to check whether the entered phone numbers are not an empty string, follows the standard phone number format that contains only numerals and is prefixed by a '+' symbol. 2. `getFormdetails()` - This function gets the input phone number details of the customer and the sales person's number entered by the user. The phone numbers are validated by calling the `validateData()` function. On successful validation of both the phone numbers, an ajax call is made to the `/makeCall` route. It initiates an outbound call from the sales team's contact number to the customer's mobile number, and renders a response back to the client once the call is initiated. 3. `getRequiredData()` - This function is used to set the columns of the call logs with respect to the call data retrieved by querying the DataStore in `/getLogs` route. 4. `renderTable()` - This function gets the data from the `getRequiredData()` function and renders it back in the client to display the call logs. 5. `showDialer()`** - This function is executed on click of the **'View Dialer'** button. 6. **`showCallLogs()`** - This function is executed on click of the **'View Call Logs'** button and triggers the **`loadLog()` function. 7. `loadLog()` - This function makes an ajax call to the `/getLogs` route defined in the Advanced I/O function to fetch the call log details and render them in the client. The Advanced I/O function defines the following APIs that perform various actions: 1. `/makeCall` Obtains the sales team's contact number and customer's phone number data from the `getFormDetails()` function. Inserts the phone number details in the `CallLog()` table in the DataStore. An outbound call is initiated by calling Twilio's Voice API and also sending the TwiML instructions defined in the `/outbound` route as a part of the API request. 2. `/outbound/:salesNumber`** Defines the TwiML instructions sent to Twilio that will be executed when a call is initialized. In our Dialer application we have used the **Dial()** verb of Twilio to route a call to the sales number from Twilio's phone number. And the **Say()** verb to specify the message to be presented when the sales person is awaiting a response from the customer's end. 3. **`/statusCheck` On completion of a call, this route sends relevant call information, such as call duration, call status, called country and timestamp, to the respective columns in the CallLogs table. 4. `/getLogs`** Executes the ZCQL query to fetch the call data from the CallLogs table. The query result returns the sales team's contact number, customer mobile number, duration of the call, timestamp of the call, status of the call and the country from which the call was initiated.