<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Olasunkanmi Balogun</title>
    <description>The latest articles on Forem by Olasunkanmi Balogun (@sukodes).</description>
    <link>https://forem.com/sukodes</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F680985%2Fd38724cb-f2c8-493a-9c16-8504ca3702e9.jpg</url>
      <title>Forem: Olasunkanmi Balogun</title>
      <link>https://forem.com/sukodes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sukodes"/>
    <language>en</language>
    <item>
      <title>How I Built a Decentralized Crowdfunding App with Foundry(incl. unit tests)</title>
      <dc:creator>Olasunkanmi Balogun</dc:creator>
      <pubDate>Mon, 09 Sep 2024 12:55:40 +0000</pubDate>
      <link>https://forem.com/sukodes/how-i-built-a-decentralized-crowdfunding-app-with-foundryincl-unit-tests-1kma</link>
      <guid>https://forem.com/sukodes/how-i-built-a-decentralized-crowdfunding-app-with-foundryincl-unit-tests-1kma</guid>
      <description>&lt;p&gt;Recently, I completed the &lt;a href="https://www.youtube.com/watch?v=GWLxIYAIMqQ&amp;amp;list=PL2-Nvp2Kn0FPH2xU3IbKrrkae-VVXs1vk" rel="noopener noreferrer"&gt;Foundry Solidity Smart Contract&lt;/a&gt; course by &lt;a href="https://x.com/PatrickAlphaC" rel="noopener noreferrer"&gt;Patrick Collins&lt;/a&gt;. Throughout the course, I gained hands-on experience with generating randomness on blockchains using &lt;a href="https://docs.chain.link/vrf/v2/getting-started" rel="noopener noreferrer"&gt;Chainlink VRF&lt;/a&gt;, working with ERC20s and NFTs, exploring DeFi, building upgradeable smart contracts, and diving into DAOs—all using the powerful tools provided by &lt;a href="https://getfoundry.sh" rel="noopener noreferrer"&gt;Foundry&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;To cement some of the concepts I had learned, I decided to get my hands dirty by building a Crowdfunding dApp which will be discussed in this article. &lt;/p&gt;

&lt;p&gt;This article will cover a range of beginner-friendly concepts, from using &lt;code&gt;struct&lt;/code&gt; to define complex data types, utilizing &lt;code&gt;mappings&lt;/code&gt; to store and access campaign data efficiently, and implementing &lt;code&gt;require&lt;/code&gt; statements to enforce critical conditions and ensure contract integrity.  You'll also learn how to send ETH to a function securely and declare custom error types in Solidity to handle exceptions. Additionally, I'll walk you through writing comprehensive tests in Solidity to validate your contract’s functionality.&lt;/p&gt;

&lt;p&gt;Finally, we'll generate an RPC URL with &lt;a href="https://www.alchemy.com/" rel="noopener noreferrer"&gt;Alchemy&lt;/a&gt; to interact with the blockchain seamlessly and explore how to deploy your contracts on the Sepolia testnet. &lt;/p&gt;

&lt;p&gt;Better yet, we'll put all of this into practice using a real code editor—preferably VSCode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A solid understanding of fundamental blockchain concepts, particularly smart contracts, and their functionality.&lt;/li&gt;
&lt;li&gt;Basic familiarity with Solidity for writing smart contracts, including key concepts such as functions, modifiers, events, and error handling (though I will briefly explain them throughout the article).&lt;/li&gt;
&lt;li&gt;A working knowledge of &lt;code&gt;Makefiles&lt;/code&gt; and their use in automating project setups.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you're ready, let's dive in! 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  Foundry installation &amp;amp; project setup
&lt;/h2&gt;

&lt;p&gt;Foundry is a comprehensive toolchain for smart contract development. It handles your dependencies, compiles your project, runs tests, deploys contracts, and enables interaction with the blockchain via the command line and Solidity scripts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you're new to Foundry and using Windows, you'll need to use the WSL as your terminal, since Foundry doesn't currently support Powershell or the command prompt.&lt;/p&gt;

&lt;p&gt;For first-time Foundry users, open your terminal and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -L https://foundry.paradigm.xyz | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install &lt;code&gt;Foundryup&lt;/code&gt;. Simply follow the on-screen instructions to make the &lt;code&gt;Foundryup&lt;/code&gt; command available in your CLI. &lt;/p&gt;

&lt;p&gt;Next, run the &lt;code&gt;Foundryup&lt;/code&gt; command in your terminal. This will install the latest (nightly) precompiled binaries: &lt;a href="https://book.getfoundry.sh/forge/" rel="noopener noreferrer"&gt;&lt;code&gt;forge&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://book.getfoundry.sh/cast/" rel="noopener noreferrer"&gt;&lt;code&gt;cast&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://book.getfoundry.sh/anvil/" rel="noopener noreferrer"&gt;&lt;code&gt;anvil&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://book.getfoundry.sh/chisel/" rel="noopener noreferrer"&gt;&lt;code&gt;chisel&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once installation is complete, open your code editor, navigate to your projects folder, and create a directory for the crowdfunding dApp project we're about to build. For this tutorial, I'll name mine &lt;code&gt;crowdfunding-dApp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, to initialize a Foundry application, run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forge init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If successful, your project structure should appear like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fum7xviphrb75lg8rqitl.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fum7xviphrb75lg8rqitl.PNG" alt="Foundry app project structure" width="251" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;src&lt;/code&gt; folder, you'll find boilerplate code for a &lt;code&gt;counter&lt;/code&gt; contract, with corresponding scripts and tests in the &lt;code&gt;script&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; folders. Delete these files so we can start our project from scratch.&lt;/p&gt;

&lt;p&gt;This takes us to the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developing the Crowdfunding Smart Contract
&lt;/h2&gt;

&lt;p&gt;Before diving into the implementation, let’s outline the key features of this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a function that allows users to launch campaigns with a specific funding goal and deadline. This function should &lt;code&gt;revert&lt;/code&gt; with an error if the specified deadline is in the past.&lt;/li&gt;
&lt;li&gt;Develop a function that enables donors to contribute to a campaign by sending funds to the campaign creator’s address. This function should &lt;code&gt;revert&lt;/code&gt; with an error in the following scenarios:

&lt;ul&gt;
&lt;li&gt;If the donor sends zero ETH.&lt;/li&gt;
&lt;li&gt;If the campaign’s deadline has already passed.&lt;/li&gt;
&lt;li&gt;If the campaign’s funding target has already been reached.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;For each of these conditions, we’ll define custom errors.&lt;/p&gt;

&lt;p&gt;To get started, create a new file in your &lt;code&gt;src&lt;/code&gt; folder named &lt;code&gt;crowdfunding.sol&lt;/code&gt;. This file will contain the smart contract code for our crowdfunding dApp.&lt;/p&gt;

&lt;p&gt;Begin by pasting the following code, which specifies the Solidity version and defines the contract. Notice that we have also defined the custom errors we'll use throughout the contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

contract Crowdfunding {
    error Crowdfunding__DeadlineMustBeInTheFuture();
    error Crowdfunding__CantSendZeroEth();
    error Crowdfunding__CampaignDeadlineElapsed();
    error Crowdfunding__TargetMetForCampaign();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we’ll outline the campaign structure using the &lt;code&gt;struct&lt;/code&gt; keyword and declare the necessary state variables. Inside the contract, add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct Campaign {
    address owner;
    string title;
    string description;
    uint256 target;
    uint256 deadline;
    uint256 amountCollected;
    string image;
    address[] donators;
    uint256[] donations;
}

mapping(uint256 =&amp;gt; Campaign) public campaigns;
uint256 public campaignId = 0;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this snippet, we define a &lt;code&gt;struct&lt;/code&gt; to represent each campaign, and we declare a &lt;code&gt;mapping&lt;/code&gt; variable that links a &lt;code&gt;uint256&lt;/code&gt; type to the &lt;code&gt;Campaign&lt;/code&gt; struct. If you’re familiar with JavaScript, you can think of a mapping as an object that stores data in key-value pairs.&lt;/p&gt;

&lt;p&gt;Lastly, we introduced a &lt;code&gt;campaignId&lt;/code&gt; variable, which will serve as the key for our mappings as we add new campaigns.&lt;/p&gt;

&lt;p&gt;With this foundation in place, we’re ready to start creating the contract functions. &lt;/p&gt;

&lt;p&gt;To begin, we'll create a function that allows users to launch a campaign. Add the following code snippet to your file. Comments have been included to clarify each part:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function createCampaign(
    address _owner,
    string memory _title,
    string memory _description,
    uint256 _target,
    uint256 _deadline,
) public returns (uint256) {
    Campaign storage campaign = campaigns[campaignId]; // Assign a key to the mapping

    if (_deadline &amp;lt; block.timestamp) {
        revert Crowdfunding__DeadlineMustBeInTheFuture();
    }
    // Populate the campaign details using the provided input
    campaign.owner = _owner;
    campaign.title = _title;
    campaign.description = _description;
    campaign.target = _target;
    campaign.deadline = _deadline;
    campaign.amountCollected = 0;

    campaignId++; // Increment the state value after a new campaign is added
    return campaignId - 1; // Return the index of the newly created campaign
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;createCampaign&lt;/code&gt; function is designed to allow users to create new crowdfunding campaigns on the blockchain. It takes several parameters, including the campaign &lt;code&gt;owner&lt;/code&gt;'s address, the &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; of the campaign, the funding target, and the deadline for the campaign. The function first checks if the provided deadline is in the future; if it's not, the function reverts with an error, &lt;code&gt;Crowdfunding__DeadlineMustBeInTheFuture()&lt;/code&gt;. If the &lt;code&gt;deadline&lt;/code&gt; is valid, the function then stores the campaign details in a mapping using the current &lt;code&gt;campaignId&lt;/code&gt; as the key. &lt;/p&gt;

&lt;p&gt;After storing the campaign information, the function increments the &lt;code&gt;campaignId&lt;/code&gt; to ensure each new campaign gets a unique identifier. It finally returns the &lt;code&gt;id&lt;/code&gt; of the newly created campaign. This &lt;code&gt;id&lt;/code&gt; can be used to reference the campaign for future actions, like making donations. The function essentially sets up the campaign's foundation, ensuring it has all the necessary information and a unique identifier for tracking.&lt;/p&gt;

&lt;p&gt;Next, we'll implement the function for donating to the campaign. Add the below function to your contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function donateToCampaign(uint256 _campaignId) public payable {
        // revert if donor isnt sending anything
        if (msg.value &amp;lt;= 0) {
            revert Crowdfunding__CantSendZeroEth();
        }
        //  revert if deadline is in the past
        if (campaigns[_campaignId].deadline &amp;lt; block.timestamp) {
            revert Crowdfunding__CampaignDeadlineElapsed();
        }
        // revert if target is met
        if (campaigns[_campaignId].amountCollected == campaigns[_campaignId].target) {
            revert Crowdfunding__TargetMetForCampaign();
        }

        Campaign storage campaign = campaigns[_campaignId];

        uint256 remainingFundsNeeded = campaign.target - campaign.amountCollected;
        // Handle contributions based on the remaining funds needed
        // next code block optimized for CEI
        if (msg.value &amp;lt;= remainingFundsNeeded) {
            campaign.amountCollected += msg.value;
            campaign.donators.push(msg.sender);
            campaign.donations.push(msg.value);
            (bool callSuccess,) = payable(getCampaign(_campaignId).owner).call{value: msg.value}("");
            // reupdate state variables
            if (!callSuccess) {
                campaign.amountCollected -= msg.value;
                campaign.donators.pop();
                campaign.donations.pop();
            }
        } else {
            // Handle excess contributions and refunds
            uint256 excessAmount = msg.value - remainingFundsNeeded;
            uint256 amountToDonate = msg.value - excessAmount;

            // Refund the excess amount to the contributor
            payable(msg.sender).transfer(excessAmount);

            // Update the total contributions with the amount that was supposed to be donated
            campaign.amountCollected += amountToDonate;
            campaign.donators.push(msg.sender);
            campaign.donations.push(amountToDonate);
            (bool callSuccess,) = payable(getCampaign(_campaignId).owner).call{value: amountToDonate}("");
            if (!callSuccess) {
                campaign.amountCollected -= amountToDonate;
                campaign.donators.pop();
                campaign.donations.pop();
            }
        }
    }

function getCampaign(uint256 _campaignId) public view returns (Campaign memory) {
     return campaigns[_campaignId];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code block, the &lt;code&gt;donateToCampaign&lt;/code&gt; function is designed to facilitate secure contributions to a specific crowdfunding campaign on the blockchain. It first performs several checks to ensure the donation is valid: it verifies that the donor is sending a non-zero amount of ETH, ensures that the campaign’s deadline hasn’t passed, and confirms that the campaign hasn’t already met its funding target. If any of these conditions are not met, the function reverts the transaction, preventing the donation from going through.&lt;/p&gt;

&lt;p&gt;Once the initial checks are passed, the function handles the donation by updating the campaign's total funds collected and recording the donor’s contribution. If the donation exceeds the amount needed to meet the campaign’s target, the excess is refunded to the donor, and only the necessary amount is added to the campaign’s funds. The function also attempts to transfer the donation directly to the campaign owner, and if this transfer fails, it reverts all state changes to maintain the integrity of the campaign’s data.&lt;/p&gt;

&lt;p&gt;We also implemented a getter function, &lt;code&gt;getCampaign&lt;/code&gt;, which allows users to view the details of any campaign using its unique &lt;code&gt;id&lt;/code&gt;. It provides transparency by giving access to all relevant campaign information without altering any data on the blockchain. This ensures that potential donors or interested parties can easily check the status and details of a campaign before deciding to contribute.&lt;/p&gt;

&lt;p&gt;To complete our contract, we’ll add two important getter functions: &lt;code&gt;getDonators&lt;/code&gt; and &lt;code&gt;getCampaigns&lt;/code&gt;. These functions are essential for retrieving key information about the campaigns and will be particularly useful when writing tests.&lt;/p&gt;

&lt;p&gt;In your contract, include the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function getDonators(uint256 _campaignId) public view returns (address[] memory) {
   return campaigns[_campaignId].donators;
}

function getCampaigns() public view returns (Campaign[] memory) {
    Campaign[] memory allCampaigns = new Campaign[](campaignId); // create a new array of length campaignId
    require(allCampaigns.length &amp;gt; 0, "No campaign has been created yet");
      for (uint256 i = 0; i &amp;lt; campaignId; i++) {
            allCampaigns[i] = campaigns[i];
       }
       return allCampaigns;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;getDonators&lt;/code&gt; function returns a list of all addresses that have donated to a specific campaign, allowing us to easily track contributors. The &lt;code&gt;getCampaigns&lt;/code&gt; function, on the other hand, compiles all the campaigns into an array, providing a comprehensive view of every campaign created so far.&lt;/p&gt;

&lt;p&gt;In the next section, we'll move on to writing tests for the contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the Crowdfunding Smart Contract
&lt;/h2&gt;

&lt;p&gt;In Foundry, each time a test is run, the contract is deployed on the local Anvil chain, typically through a &lt;code&gt;setup&lt;/code&gt; configuration. This ensures that a new contract is deployed for each test, providing a clean state for every test case.&lt;/p&gt;

&lt;p&gt;However, I like to separate the deployment logic from the tests themselves by implementing a deployment script independently of the tests—though this isn't strictly necessary. If this seems unclear now, don't worry—you’ll get more insights in the next sub-section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing the deploy script
&lt;/h3&gt;

&lt;p&gt;First, create a new file in the &lt;code&gt;script&lt;/code&gt; folder of your project and name it &lt;code&gt;DeployCrowdfunding.s.sol&lt;/code&gt;. This follows the standard naming convention for script files and is where we'll write our deployment logic.&lt;/p&gt;

&lt;p&gt;Paste the following code into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//  SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

import {Script} from "forge-std/Script.sol";
import {Crowdfunding} from "../src/Crowdfunding.sol";

contract DeployCrowdfunding is Script {
    function run() external returns (Crowdfunding) {
        vm.startBroadcast();
        Crowdfunding crowdfunding = new Crowdfunding();
        vm.stopBroadcast();
        return crowdfunding;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script above begins by importing necessary modules, including the &lt;code&gt;Script&lt;/code&gt; from &lt;a href="https://book.getfoundry.sh/forge/forge-std" rel="noopener noreferrer"&gt;forge-std&lt;/a&gt;, a standard utility for writing scripts in Foundry. The &lt;code&gt;DeployCrowdfunding&lt;/code&gt; contract, which &lt;a href="https://solidity-by-example.org/inheritance/" rel="noopener noreferrer"&gt;inherits&lt;/a&gt; the &lt;code&gt;Script&lt;/code&gt; contract, defines a run function that is automatically executed when the script is run. Within this function, the deployment process is bracketed by &lt;a href="https://book.getfoundry.sh/cheatcodes/start-broadcast" rel="noopener noreferrer"&gt;&lt;code&gt;vm.startBroadcast()&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://book.getfoundry.sh/cheatcodes/stop-broadcast" rel="noopener noreferrer"&gt;&lt;code&gt;vm.stopBroadcast()&lt;/code&gt;&lt;/a&gt;, which signal the beginning and end of the broadcasted deployment on the blockchain. The &lt;code&gt;Crowdfunding&lt;/code&gt; contract is then instantiated and deployed, and the resulting contract instance is returned. &lt;/p&gt;

&lt;p&gt;With this, we have handled the deployment of the &lt;code&gt;Crowdfunding&lt;/code&gt; contract, we can now go ahead to write tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing Tests
&lt;/h3&gt;

&lt;p&gt;Here's a quick breakdown of the tests we will be writing; these tests will cover a range of scenarios to guarantee the robustness of our contract.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;testCampaignCreationRevertsIfDeadlineIsNotInTheFuture&lt;/strong&gt;: When a user attempts to create a campaign with a date that's in the past—this test ensures that such attempts are blocked, safeguarding against illogical campaign setups.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;testCreateCampaign&lt;/strong&gt;: This is the core test that verifies if a campaign can be successfully created. We'll check that all the campaign details, like the title, description, target, and deadline, are stored correctly and accessible through the contract.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;testDonationRevertsWhenZeroEthIsDonated&lt;/strong&gt;: This test ensures our contract correctly rejects any attempts to donate without sending ETH, preventing empty contributions from slipping through.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;testDonationRevertsWhenDeadlinePasses&lt;/strong&gt;: Donations should only be accepted within the campaign's active period. This test ensures that the contract stops accepting donations once the deadline has passed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;testDonationRevertsWhenTargetIsMet&lt;/strong&gt;: When a campaign hits its target, there's no need for further contributions. This test verifies that the contract prevents overfunding and respects the campaign's goals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;testDonateToCampaign&lt;/strong&gt;: Here, we'll ensure that donations are processed correctly—funds are received, campaign balances are updated, and the donor’s details are recorded accurately.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;testReverseExcessAmountToSender&lt;/strong&gt;: Sometimes, a donor might send more ETH than needed to reach the target. This test ensures that any excess funds are returned to the sender, maintaining fairness and transparency.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each of these tests ensures that our crowdfunding platform works securely, and ultimately, as intended. Now, let's start implementing the test contract. &lt;/p&gt;

&lt;p&gt;Navigate to the &lt;code&gt;test&lt;/code&gt; folder and create a new file named &lt;code&gt;CrowdfundingTests.t.sol&lt;/code&gt;, this follows the standard naming convention for test files. Paste the following code into the newly created file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

import {Test} from "forge-std/Test.sol";
import {Crowdfunding} from "../src/Crowdfunding.sol";
import {DeployCrowdfunding} from "../script/DeployCrowdfunding.s.sol";

contract CrowdfundingTests is Test {
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we've laid the foundation for our test suite. The &lt;code&gt;Test&lt;/code&gt; contract from the Foundry standard library provides us with a range of tools to simulate blockchain transactions and verify that our contract behaves as expected. &lt;/p&gt;

&lt;p&gt;We've also imported our &lt;code&gt;Crowdfunding&lt;/code&gt; contract from the &lt;code&gt;src&lt;/code&gt; folder, which will serve as the focus of our tests. Additionally, we imported the &lt;code&gt;DeployCrowdfunding&lt;/code&gt; contract from the &lt;code&gt;script&lt;/code&gt; folder to handle the deployment of our &lt;code&gt;Crowdfunding&lt;/code&gt; contract when we run tests. Finally, we declared the &lt;code&gt;CrowdfundingTests&lt;/code&gt; contract, which inherits the &lt;code&gt;Test&lt;/code&gt; contract.&lt;/p&gt;

&lt;p&gt;To effectively simulate the creation of a campaign and the process of making donations, we need to set up some initial parameters that will be used across our test functions. These parameters are crucial for mimicking real-world scenarios where multiple users interact with our contract.&lt;/p&gt;

&lt;p&gt;Paste the code below inside the &lt;code&gt;CrowdfundingTests&lt;/code&gt; contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Crowdfunding crowdFunding;
address owner = makeAddr("user");
address donor1 = makeAddr("donor1");
address donor2 = makeAddr("donor2");

uint256 campaignId;
string constant TITLE = "Help Fund My Project";
string constant DESCRIPTION = "A project that will change the world!";
uint256 constant TARGET = 5 ether;
uint256 deadline = block.timestamp + 7 days;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the first line, we declared an instance of the &lt;code&gt;Crowdfunding&lt;/code&gt; contract. This instance will allow us to directly interact with the contract’s external functions during our tests.&lt;/p&gt;

&lt;p&gt;Next, we define addresses for the owner and two donors. The &lt;code&gt;makeAddr&lt;/code&gt; function is a utility from the Foundry framework that generates Ethereum addresses for testing purposes. These addresses represent the different actors in our crowdfunding scenario, with the &lt;code&gt;owner&lt;/code&gt; being the campaign creator and the &lt;code&gt;donors&lt;/code&gt; being contributors to the campaign.&lt;/p&gt;

&lt;p&gt;We then introduce a &lt;code&gt;campaignId&lt;/code&gt;, which will store the unique identifier of the campaign created during the tests. This &lt;code&gt;id&lt;/code&gt; is essential for referencing specific campaigns, especially when testing multiple campaign creations.&lt;/p&gt;

&lt;p&gt;Lastly, we implement parameters needed to simulate a realistic campaign which are passed as arguments when creating a campaign.&lt;/p&gt;

&lt;p&gt;With the initial setup complete, we can start writing our actual tests. However, before diving into the individual test cases, it's essential to configure a &lt;code&gt;setUp&lt;/code&gt; function. This function, which we mentioned earlier, ensures that each test begins with a fresh and consistent state, making our testing process more reliable. &lt;/p&gt;

&lt;p&gt;Paste the code snippet below into your &lt;code&gt;CrowdfundingTest&lt;/code&gt; contract to configure the &lt;code&gt;setup&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function setUp() public {
   DeployCrowdfunding deployCrowdFunding = new DeployCrowdfunding();
   crowdFunding = deployCrowdFunding.run();
   vm.deal(owner, 10 ether);
   vm.deal(donor1, 5 ether);
   vm.deal(donor2, 5 ether);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first line within the &lt;code&gt;setUp&lt;/code&gt; function creates a new instance of the &lt;code&gt;DeployCrowdfunding&lt;/code&gt; contract. &lt;/p&gt;

&lt;p&gt;Next, we call the &lt;code&gt;run&lt;/code&gt; function within the &lt;code&gt;DeployCrowdfunding&lt;/code&gt; contract, which handles the actual deployment of the &lt;code&gt;Crowdfunding&lt;/code&gt; contract as we implemented in the script.&lt;/p&gt;

&lt;p&gt;The last three lines use a Foundry &lt;a href="https://book.getfoundry.sh/forge/cheatcodes" rel="noopener noreferrer"&gt;&lt;code&gt;cheatcode&lt;/code&gt;&lt;/a&gt; to simulate funding the &lt;code&gt;owner&lt;/code&gt; and &lt;code&gt;donor&lt;/code&gt; addresses with specific amounts of ETH. The &lt;a href="https://book.getfoundry.sh/cheatcodes/deal" rel="noopener noreferrer"&gt;vm.deal&lt;/a&gt; function is used to assign these addresses a starting balance, ensuring that they have sufficient funds to participate in the campaign creation and donation processes during the tests.&lt;/p&gt;

&lt;p&gt;With the foundational setup in place, it's time to start writing our tests. We'll begin with the first test on our list: &lt;code&gt;testCampaignCreationRevertsIfDeadlineIsNotInTheFuture&lt;/code&gt;. This test is designed to ensure that the contract correctly handles scenarios where a campaign is created with a deadline that has already passed. The goal is to confirm that the contract will revert the transaction, preventing the creation of invalid campaigns.&lt;/p&gt;

&lt;p&gt;To implement this test, paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function testCampaignCreationRevertsIfDeadlineIsNotInTheFuture() public {
    vm.warp(block.timestamp + deadline + 1);
        vm.expectRevert(Crowdfunding.Crowdfunding__DeadlineMustBeInTheFuture.selector);
    vm.prank(owner);
    crowdFunding.createCampaign(owner, TITLE, DESCRIPTION, TARGET, deadline);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test starts by using &lt;code&gt;vm.warp(block.timestamp + deadline + 1);&lt;/code&gt;, which advances the blockchain's internal clock to a point just beyond the intended deadline. This simulates a scenario where the current time is already past the campaign's deadline. Learn more about &lt;code&gt;vm.warp&lt;/code&gt; &lt;a href="https://book.getfoundry.sh/cheatcodes/warp" rel="noopener noreferrer"&gt;here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, the &lt;code&gt;vm.expectRevert(Crowdfunding.Crowdfunding__DeadlineMustBeInTheFuture.selector);&lt;/code&gt; line expects a revert when the next function is called. Specifically, it expects the revert reason to match the custom error &lt;code&gt;Crowdfunding__DeadlineMustBeInTheFuture&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, &lt;code&gt;vm.prank(owner);&lt;/code&gt; simulates a transaction sent from the owner's address, followed by the call to &lt;code&gt;crowdfunding.createCampaigns(owner, TITLE, DESCRIPTION, TARGET, deadline);&lt;/code&gt;. This line attempts to create a campaign with an expired deadline. Since the deadline is in the past, the contract should revert, confirming that our validation logic is working as intended.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: To check if every test runs successfully, run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forge test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we have only written one test so far, a successful run will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff5vsklwhdtbmgp38brb0.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff5vsklwhdtbmgp38brb0.PNG" alt="Forge test result" width="794" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next test, &lt;code&gt;testCreateCampaign&lt;/code&gt;, will simulate the behavior of the &lt;code&gt;createCampaign&lt;/code&gt; function. Since creating a campaign and retrieving the &lt;code&gt;campaignId&lt;/code&gt; will be necessary for several upcoming tests, let's streamline the process by creating a &lt;a href="https://solidity-by-example.org/function-modifier/" rel="noopener noreferrer"&gt;modifier&lt;/a&gt; that we can reuse throughout the test suite.&lt;/p&gt;

&lt;p&gt;Add this modifier to your test contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;modifier createCampaign() {
   vm.prank(owner);
   campaignId = crowdFunding.createCampaign(owner, TITLE, DESCRIPTION, TARGET, deadline);
   _;
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above, we created a modifier named &lt;code&gt;createCampaign&lt;/code&gt; that helps us automate the creation of a campaign by calling the &lt;code&gt;createCampaign&lt;/code&gt; function with the predefined values &lt;code&gt;owner&lt;/code&gt;, &lt;code&gt;TITLE&lt;/code&gt;, &lt;code&gt;DESCRIPTION&lt;/code&gt;, &lt;code&gt;TARGET&lt;/code&gt;, and &lt;code&gt;deadline&lt;/code&gt;. It uses &lt;code&gt;vm.prank(owner)&lt;/code&gt; to simulate transactions as the owner account. The &lt;code&gt;campaignId&lt;/code&gt; generated from this creation is then stored and can be reused in subsequent tests. Lastly, the &lt;code&gt;_;&lt;/code&gt; in the modifier allows the test function to execute after the campaign is created.&lt;/p&gt;

&lt;p&gt;Now that the modifier is in place, let's proceed with the actual &lt;code&gt;testCreateCampaign&lt;/code&gt; function, which ensures that campaigns are created as expected. Add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function testCreateCampaign() public createCampaign {
    string memory campaignTitle = crowdFunding.getCampaign(campaignId).title;
    string memory campaignDescription = crowdFunding.getCampaign(campaignId).description;
    uint256 campaignTarget = crowdFunding.getCampaign(campaignId).target;
    uint256 campaignDeadline = crowdFunding.getCampaign(campaignId).deadline;
    uint256 campaignAmountCollected = crowdFunding.getCampaign(campaignId).amountCollected;

    assertEq(owner, owner);
    assertEq(campaignTitle, TITLE);
    assertEq(campaignDescription, DESCRIPTION);
    assertEq(campaignTarget, TARGET);
    assertEq(campaignDeadline, deadline);
    assertEq(campaignAmountCollected, 0);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you'll notice, the function above uses the &lt;code&gt;createCampaign&lt;/code&gt; modifier to create a campaign, ensuring that we don't manually repeat the process in every test. &lt;/p&gt;

&lt;p&gt;It then retrieves the created campaign's details &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;target&lt;/code&gt;, &lt;code&gt;deadline&lt;/code&gt;, and &lt;code&gt;amount collected&lt;/code&gt; using the getCampaign function defined in the &lt;code&gt;Crowdfunding&lt;/code&gt; contract. Each of these values is stored in memory to be compared with the expected values (predefined in the test).&lt;/p&gt;

&lt;p&gt;Finally, the &lt;a href="https://book.getfoundry.sh/reference/forge-std/assertEq" rel="noopener noreferrer"&gt;&lt;code&gt;assertEq&lt;/code&gt;&lt;/a&gt; statements verify that the campaign’s actual values match the expected inputs. The assertions ensure the owner is correct, confirm the &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;target&lt;/code&gt;, and &lt;code&gt;deadline&lt;/code&gt; match the provided values during creation, and lastly, verify that the initial amount collected is 0, as no donations have been made yet.&lt;/p&gt;

&lt;p&gt;The next test we'll implement is the &lt;code&gt;testDonationRevertsWhenZeroEthIsDonated&lt;/code&gt;; which ensures that zero eth isn't donated to a campaign. Here's the code you need to add to your test contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; function testDonationRevertsWhenZeroEthIsDonated() public createCampaign {
  vm.expectRevert(Crowdfunding.Crowdfunding__CantSendZeroEth.selector);
  // Donate to the campaign
  vm.prank(donor1);
  crowdFunding.donateToCampaign{value: 0}(campaignId);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should already be acquainted with the Foundry cheatcodes used in this test from the first one. The main distinction here is that we're invoking the &lt;code&gt;donateToCampaign&lt;/code&gt; function while sending zero ETH.&lt;/p&gt;

&lt;p&gt;Now, let's proceed to the next test, &lt;code&gt;testDonationRevertsWhenDeadlinePasses&lt;/code&gt;, which ensures that donations are rejected once the campaign deadline has expired.&lt;/p&gt;

&lt;p&gt;Paste the following code in your contract to implement this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function testDonationRevertsWhenDeadlinePasses() public createCampaign {
     vm.warp(block.timestamp + deadline + 1);
     vm.expectRevert();
     // Donate to the campaign
     vm.prank(donor1);
     crowdFunding.donateToCampaign{value: 2 ether}(campaignId);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;donor1&lt;/code&gt; is unable to send the &lt;code&gt;2 ether&lt;/code&gt; to the campaign owner because the campaign deadline has already passed.&lt;/p&gt;

&lt;p&gt;Next up is the &lt;code&gt;testDonationRevertsWhenTargetIsMet&lt;/code&gt; test, which checks that a donation is rejected once the campaign's funding target has been reached, as its name suggests.&lt;/p&gt;

&lt;p&gt;Add the following code to implement this function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function testDonationRevertsWhenTargetIsMet() public createCampaign {
   vm.prank(donor1);
   crowdFunding.donateToCampaign{value: 5 ether}(campaignId); 
   vm.expectRevert(Crowdfunding.Crowdfunding__TargetMetForCampaign.selector);
   vm.prank(donor2);
   crowdFunding.donateToCampaign{value: 1 ether}(campaignId);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this test, we simulate two donors contributing to the same campaign. The first donor meets the campaign's funding target by sending the required amount of ETH. The second donor's attempt to donate should therefore trigger a revert since the target has already been reached.&lt;/p&gt;

&lt;p&gt;That concludes the tests for the revert scenarios. Next, we'll move on to testing another core functionality of the contract with the &lt;code&gt;testDonateToCampaign&lt;/code&gt; test. This test verifies that donations to a campaign are handled correctly. Below is the code that implements this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function testDonateToCampaign() public createCampaign {
    // Donate to the campaign
    vm.prank(donor1);
    crowdFunding.donateToCampaign{value: 2 ether}(campaignId);

    // Validate campaign donation data
    uint256 campaignAmountCollected = crowdFunding.getCampaign(campaignId).amountCollected;
    uint256[] memory donations = crowdFunding.getCampaign(campaignId).donations;
    address[] memory donators = crowdFunding.getCampaign(campaignId).donators;

    assert(campaignAmountCollected == 2 ether);
    assertEq(donators.length, 1);
    assertEq(donations[0], 2 ether);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this test, &lt;code&gt;donor1&lt;/code&gt; donates &lt;code&gt;2 ether&lt;/code&gt; to the campaign. We then validate that the campaign correctly tracks the amount collected, the donations made, and the donor's address. The &lt;code&gt;assert&lt;/code&gt; statements ensure that &lt;code&gt;2 ether&lt;/code&gt; is properly reflected in the campaign's data, and that &lt;code&gt;donor1&lt;/code&gt; is listed as the sole contributor with the correct donation amount.&lt;/p&gt;

&lt;p&gt;Next, we’ll test the contract's ability to return excess funds to the donor if they send more &lt;code&gt;ether&lt;/code&gt; than is needed to meet the campaign’s target. The code below demonstrates how this is implemented:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function testReverseExcessAmountToSender() public createCampaign {
    vm.prank(donor1);
    crowdFunding.donateToCampaign{value: 2 ether}(campaignId);
    vm.prank(donor2);
    crowdFunding.donateToCampaign{value: 4 ether}(campaignId);
    assertEq(donor2.balance, 2 ether);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this test, &lt;code&gt;donor1&lt;/code&gt; donates &lt;code&gt;2 ether&lt;/code&gt; to the campaign, and &lt;code&gt;donor2&lt;/code&gt; attempts to donate &lt;code&gt;4 ether&lt;/code&gt;. However, since the campaign only needs 2 more &lt;code&gt;ether&lt;/code&gt; to meet its target, the contract should accept the necessary amount and return the extra &lt;code&gt;2 ether&lt;/code&gt; to &lt;code&gt;donor2&lt;/code&gt;. The final &lt;code&gt;assertEq&lt;/code&gt; statement verifies that &lt;code&gt;donor2&lt;/code&gt;'s balance reflects the excess &lt;code&gt;ether&lt;/code&gt; refund. This ensures that the contract correctly handles over-contributions.&lt;/p&gt;

&lt;p&gt;So far, we’ve tested the key functionalities of our contract. Now, to check how much of our code is covered by these tests, you can run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forge coverage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output should resemble something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxpud0dlr2yto41f2ofy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxpud0dlr2yto41f2ofy.png" alt="Forge coverage" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we've already covered a significant portion. However, if you'd like to dive deeper and challenge yourself, you can write additional tests, particularly for the getter functions in the contract.&lt;/p&gt;

&lt;p&gt;The final step is deploying the smart contract, which will be discussed in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying Your Contract Locally and on the Sepolia Testnet
&lt;/h2&gt;

&lt;p&gt;With Foundry, you can deploy your contract either locally using &lt;a href="https://book.getfoundry.sh/reference/anvil/" rel="noopener noreferrer"&gt;&lt;code&gt;anvil&lt;/code&gt;&lt;/a&gt; or directly on a testnet. In this section, I'll guide you through both deployment methods. We will manage both scenarios using a &lt;a href="https://makefiletutorial.com/" rel="noopener noreferrer"&gt;&lt;code&gt;Makefile&lt;/code&gt;&lt;/a&gt;, so ensure that &lt;code&gt;make&lt;/code&gt; is installed on your system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying on a Local Chain
&lt;/h3&gt;

&lt;p&gt;For both local and testnet deployments, you'll need separate private keys and RPC URLs. In this subsection, I'll walk you through deploying the contract locally on a simulated blockchain.&lt;/p&gt;

&lt;p&gt;To begin, open your terminal and run the &lt;code&gt;anvil&lt;/code&gt; command. This will generate a list of private keys and a localhost URL (typically &lt;code&gt;https://localhost:8545&lt;/code&gt;), which will serve as your RPC URL for the local deployment.&lt;/p&gt;

&lt;p&gt;Once you have your private key and RPC URL, create a &lt;code&gt;Makefile&lt;/code&gt; in the root folder of your project. At this stage, your project folder structure should look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4avjgenwn4isf5a0dcg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4avjgenwn4isf5a0dcg.png" alt="Folder structure" width="246" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, paste the following into your Makefile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="k"&gt;-include&lt;/span&gt;&lt;span class="sx"&gt; .env&lt;/span&gt;

&lt;span class="nv"&gt;DEFAULT_ANVIL_KEY&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; your-anvil-private-key

&lt;span class="c"&gt;# Default deployment uses anvil
&lt;/span&gt;&lt;span class="nv"&gt;NETWORK_ARGS&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; http://localhost:8545 &lt;span class="nt"&gt;--private-key&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;DEFAULT_ANVIL_KEY&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--broadcast&lt;/span&gt;

&lt;span class="nl"&gt;deploy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;forge script script/DeployCrowdfunding.s.sol:DeployCrowdfunding &lt;span class="p"&gt;$(&lt;/span&gt;NETWORK_ARGS&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Make sure to replace &lt;code&gt;your-anvil-private-key&lt;/code&gt; with one of the private keys generated by &lt;code&gt;anvil&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To deploy the contract, run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the deployment is successful, the output will look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsz47qnncguwpe2gktbh7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsz47qnncguwpe2gktbh7.png" alt="Anvil chain successful deployment" width="800" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying to the Sepolia Testnet
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; To deploy on a testnet, you'll need a virtual wallet like &lt;a href="https://metamask.io" rel="noopener noreferrer"&gt;Metamask&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For deployment to the Sepolia testnet, you'll need to generate your private key and RPC URL. You can follow the steps in this &lt;a href="https://docs.alchemy.com/docs/how-to-deploy-a-smart-contract-to-the-sepolia-testnet#create-your-app-and-obtain-an-api-key" rel="noopener noreferrer"&gt;guide&lt;/a&gt; to set everything up. &lt;/p&gt;

&lt;p&gt;After following the guide, you should have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Created an account on Alchemy,&lt;/li&gt;
&lt;li&gt;Set up an app and obtained an API key,&lt;/li&gt;
&lt;li&gt;Added Sepolia testnet ETH to your wallet using a faucet,&lt;/li&gt;
&lt;li&gt;Integrated your virtual wallet (such as Metamask) with your Alchemy project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition, if you don't already have an account on &lt;a href="https://etherscan.io" rel="noopener noreferrer"&gt;Etherscan&lt;/a&gt;, create one and retrieve your API key from the "API keys" page. This will allow for contract verification post-deployment. Once these steps are completed, you're ready to proceed.&lt;/p&gt;

&lt;p&gt;Now, in your project's root directory, create a &lt;code&gt;.env&lt;/code&gt; file and add the following key-value pairs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SEPOLIA_RPC_URL = "https://eth-sepolia.g.alchemy.com/v2/your-api-key"
ETHERSCAN_API_KEY = "your-etherscan-api-key"
PRIVATE_KEY = "your-metamask-private-key"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Storing these values in the &lt;code&gt;.env&lt;/code&gt; file helps keep sensitive data secure and prevents exposing it during deployment. Also, make sure the &lt;code&gt;.env&lt;/code&gt; file is added to your &lt;code&gt;.gitignore&lt;/code&gt; to avoid accidentally pushing confidential details to a public repository like GitHub.&lt;/p&gt;

&lt;p&gt;Next, you'll need to update your &lt;code&gt;Makefile&lt;/code&gt; to allow deployment to a testnet, such as Sepolia. This will enable switching between local and testnet environments seamlessly.&lt;/p&gt;

&lt;p&gt;Update your &lt;code&gt;Makefile&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="k"&gt;-include&lt;/span&gt;&lt;span class="sx"&gt; .env&lt;/span&gt;

&lt;span class="nv"&gt;DEFAULT_ANVIL_KEY&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; your-anvil-private-key

&lt;span class="c"&gt;# Default deployment on anvil
&lt;/span&gt;&lt;span class="nv"&gt;NETWORK_ARGS&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; http://localhost:8545 &lt;span class="nt"&gt;--private-key&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;DEFAULT_ANVIL_KEY&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--broadcast&lt;/span&gt;

&lt;span class="c"&gt;# Condition to deploy on Sepolia
&lt;/span&gt;&lt;span class="k"&gt;ifeq&lt;/span&gt; &lt;span class="nv"&gt;($(findstring --network sepolia,$(ARGS)),--network sepolia)&lt;/span&gt;
    &lt;span class="nv"&gt;NETWORK_ARGS&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;SEPOLIA_RPC_URL&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--private-key&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;PRIVATE_KEY&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--broadcast&lt;/span&gt; &lt;span class="nt"&gt;--verify&lt;/span&gt; &lt;span class="nt"&gt;--etherscan-api-key&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;ETHERSCAN_API_KEY&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-vvvv&lt;/span&gt;
&lt;span class="k"&gt;endif&lt;/span&gt;

&lt;span class="nl"&gt;deploy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;forge script script/DeployCrowdfunding.s.sol:DeployCrowdfunding &lt;span class="p"&gt;$(&lt;/span&gt;NETWORK_ARGS&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To deploy your contract on the Sepolia testnet, use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make deploy ARGS="--network sepolia"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup allows for easy switching between deploying locally using &lt;code&gt;anvil&lt;/code&gt; or deploying to a testnet like Sepolia.&lt;/p&gt;

&lt;p&gt;If you have sufficient ETH, the contract should deploy successfully. You’ll then be able to view the deployment details on your Alchemy dashboard. Additionally, once you paste the contract address into Etherscan, you should see that it has been successfully verified.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We've reached the end of this article, where I’ve walked you through the entire process of building, testing, and deploying a crowdfunding smart contract using Solidity, Foundry, and Makefiles. From deploying locally on &lt;code&gt;anvil&lt;/code&gt; to pushing the contract to a testnet like Sepolia, you've learned how to set up a complete development and testing environment to ensure your contract operates securely and efficiently.&lt;/p&gt;

&lt;p&gt;You can access the source code for this project &lt;a href="https://github.com/SiR-PENt/Crowdfunding-app-with-Foundry" rel="noopener noreferrer"&gt;here&lt;/a&gt;. If you have any suggestions or improvements, feel free to submit a PR or reach out via email at &lt;a href="mailto:olasunkanmiibalogun@gmail.com"&gt;olasunkanmiibalogun@gmail.com&lt;/a&gt;. You can also connect with me on &lt;a href="https://www.linkedin.com/in/olasunkanmi-balogun-23b3a4202/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article is part of my ongoing journey to landing my first role in the blockchain space. I’ll continue documenting what I build and learn along the way, so stay tuned for more content. Let’s keep building! 👊&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>foundry</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Navigating Content Management With OneEntry</title>
      <dc:creator>Olasunkanmi Balogun</dc:creator>
      <pubDate>Mon, 29 Jan 2024 13:56:29 +0000</pubDate>
      <link>https://forem.com/sukodes/navigating-content-management-with-oneentry-15m</link>
      <guid>https://forem.com/sukodes/navigating-content-management-with-oneentry-15m</guid>
      <description>&lt;p&gt;A headless CMS provides you with the flexibility to reuse your content on an unlimited number of channels. With an API, you can easily interact with your content wherever you want, regardless of the tech stack of your body (the front-end). &lt;/p&gt;

&lt;p&gt;However, as much as there are many headless providers, navigating the complexities of these tools often requires technical expertise that not all users possess. Also, many existing systems rely on third-party plugins, leaving developers vulnerable to sudden dysfunction or lack of support.&lt;/p&gt;

&lt;p&gt;Fortunately, with &lt;a href="https://oneentry.cloud" rel="noopener noreferrer"&gt;OneEntry&lt;/a&gt;, you don’t have to worry about these shortcomings. In this article, we’ll dive into OneEntry, exploring its benefits and features, including how it helps tackle these shortcomings to redefine content management without the need for technical intricacies.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is OneEntry, and Why Should You Use It?
&lt;/h2&gt;

&lt;p&gt;OneEntry is a unique solution for the most convenient content development, creation, and management. It enables you to easily port content to any platform: websites, mobile apps, commercial electronic devices (info panels, advertising boards, eMenu, etc.)&lt;/p&gt;

&lt;p&gt;One main benefit of OneEntry is that, unlike systems heavily reliant on third-party plugins, OneEntry integrates all its business logic related to content management within a simple control panel. &lt;/p&gt;

&lt;p&gt;So, how does it work? In the next section, we will explore some of its core features.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;OneEntry offers its features in the following ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;One important feature to note about OneEntry is that, unlike systems heavily reliant on third-party plugins, OneEntry integrates all its business logic related to content management within a simple control panel. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Its robust security feature for APIs, particularly protecting  APIs through the use of mTLS certificates, ensures a high level of safety and reliability. Additionally, OneEntry offers an alternative layer of protection with the option for token security. You can easily manage advanced security measures, including API protection with mTLS certificates and token options, through the centralized and user-friendly &lt;a href="https://account.oneentry.cloud/" rel="noopener noreferrer"&gt;OneEntry Personal Account&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OneEntry operates on an attribute-based system, allowing you to structure and organize content without the need for technical expertise. Creating attributes is straightforward, and the system seamlessly integrates relationship logic. &lt;/p&gt;

&lt;p&gt;You can effortlessly manage these attributes through the user-friendly admin panel, as seen in the image below. As you can see in the image below, you can conduct actions such as editing, adding, or deleting attributes within ongoing projects, all without requiring advanced technical knowledge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0jtpytlsoulrwoptlkg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0jtpytlsoulrwoptlkg.png" alt="oneentry attribute based system" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It also provides attribute validators in the admin panel, empowering you to validate data fields seamlessly. This feature enhances the system's flexibility, ensuring the accuracy and reliability of data within the attributes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe1uionwt2md657r1u3tg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe1uionwt2md657r1u3tg.png" alt="onenetry attribute validators" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It offers an innovative approach to expanding page content through the use of "blocks". This allows you to dynamically enhance and customize your pages by adding various content blocks. Whether it's text, images, or other elements, the block-based system provides a flexible and intuitive way to create engaging and dynamic content, allowing you to tailor your pages according to your specific needs and preferences.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OneEntry facilitates content storage in multiple languages, offering a versatile solution for diverse linguistic needs. You have the flexibility to add new languages seamlessly, ensuring that your content is accessible to a global audience. This enhances the system's adaptability and inclusivity, making it easy to create multilingual, diverse content within the OneEntry platform:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Factlb9gdv0124c72kxbo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Factlb9gdv0124c72kxbo.png" alt="oneentry multilingual feature" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Form operations in OneEntry streamline the process of capturing and managing data. You can effortlessly create, customize, and deploy forms, tailoring them to your specific requirements. This feature simplifies data collection and provides tools for efficient form handling, including submission tracking, data validation, and the ability to customize form behavior. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9e4w4sil7jiim5ijkwyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9e4w4sil7jiim5ijkwyg.png" alt="oneentry data management" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OneEntry's menu module stands out for its flexibility in configuring app menus. You can easily tailor the navigation structure to meet your specific app requirements, providing a seamless and user-friendly experience. This module empowers developers to create a customized and intuitive menu system, enhancing the overall usability and navigation of their applications within the OneEntry platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbyivv6wwuzt5q2lhz1r3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbyivv6wwuzt5q2lhz1r3.png" alt="oneentry app configuration" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OneEntry provides a flexible system for setting administrators' rights, allowing users to tailor and customize permissions according to specific needs. This feature empowers administrators to allocate access levels and responsibilities with precision, ensuring a secure and well-organized management structure. Users can easily adapt the system to their unique requirements, making OneEntry a versatile solution for efficiently managing administrative rights within projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbxo2cve3yx8zke0zr20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbxo2cve3yx8zke0zr20.png" alt="oneentry administrator's right" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lastly, OneEntry's technical support stands out for its multilingual capabilities. Developers can seamlessly communicate in their native language when submitting requests, and the support team responds in the same language. This makes it easy for efficient and effective collaboration.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Overall&lt;/strong&gt;, the OneEntry team is constantly working on adding new modules and functionalities to the system. as seen in the dashboard below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fme3wf9eu9mpsm9foicj2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fme3wf9eu9mpsm9foicj2.png" alt="onentry dashboard for adding new modules" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;Throughout this article, we talked about how OneEntry transcends traditional content management expectations by offering a user-friendly experience that caters to both technical and non-technical users. However, it doesn’t end here. If you want to learn more about OneEntry and Headless CMS as a whole, there are plenty of tutorials on &lt;a href="https://www.youtube.com/@headlesscms-oneentry" rel="noopener noreferrer"&gt;OneEntry's YouTube channel&lt;/a&gt; for working with the system. &lt;/p&gt;

</description>
      <category>cms</category>
      <category>webdev</category>
      <category>headless</category>
      <category>contentmanagement</category>
    </item>
    <item>
      <title>📊 How To Display An In-App Survey In Next.js 13 With Supabase And Formbricks 🤝🛠️</title>
      <dc:creator>Olasunkanmi Balogun</dc:creator>
      <pubDate>Sat, 21 Oct 2023 12:01:53 +0000</pubDate>
      <link>https://forem.com/sukodes/how-to-display-an-in-app-survey-in-nextjs-13-with-supabase-and-formbricks-1d9n</link>
      <guid>https://forem.com/sukodes/how-to-display-an-in-app-survey-in-nextjs-13-with-supabase-and-formbricks-1d9n</guid>
      <description>&lt;p&gt;Once a user has successfully completed the signup process for your application, you might consider initiating an onboarding segmentation survey for your users right away. This approach enables you to gain a deeper understanding of your users.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;In this article, you'll discover the process of implementing authentication and protected routes using &lt;a href="https://supabase.com/docs" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;. Following that, you'll explore how to effortlessly integrate an onboarding segmentation survey into your application.&lt;/p&gt;

&lt;p&gt;When you are ready, let's dive in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv27yxlijaqf0vghulxqs.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv27yxlijaqf0vghulxqs.gif" alt="Spongebob is ready" width="640" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;In this article, you will learn how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Implement authentication and protected routes with Supabase&lt;/li&gt;
&lt;li&gt;Implement an in-app onboarding segmentation survey with Formbricks.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. How to implement authentication in Next.js 13 with Supabase
&lt;/h2&gt;

&lt;p&gt;If you are unfamiliar with Supabase, it is an open-source alternative to Firebase. Among its array of products, one of the key features we will delve into is its &lt;a href="https://supabase.com/docs/guides/auth" rel="noopener noreferrer"&gt;authentication&lt;/a&gt; feature.&lt;/p&gt;

&lt;p&gt;We'll start by signing in to the &lt;a href="https://supabase.com/dashboard/projects" rel="noopener noreferrer"&gt;dashboard&lt;/a&gt; to create a project. Your dashboard looks this if you have not created a project before:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdv94ttkakiia7u36t1d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdv94ttkakiia7u36t1d.png" alt="Supabase dashboard" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, go ahead and create your project by clicking the &lt;code&gt;new project&lt;/code&gt; button. Name your project however you want; I'll name mine &lt;code&gt;Auth-with-inapp-survey&lt;/code&gt; for the purpose of this article.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzzwlm52u1ggkzf9og12z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzzwlm52u1ggkzf9og12z.png" alt="Create new project on supabase" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hit the &lt;code&gt;create new project&lt;/code&gt; button when you are done, your new project will then appear on your dashboard, this way:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttsxz77q4o06jb97mevq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttsxz77q4o06jb97mevq.png" alt="New project" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With your project successfully created, the next step is to set up your &lt;code&gt;Next.js&lt;/code&gt; project. Supabase simplifies this process by offering a pre-configured &lt;code&gt;Next.js&lt;/code&gt; project with &lt;code&gt;Supabase-auth&lt;/code&gt;, &lt;code&gt;TypeScript&lt;/code&gt;, and &lt;code&gt;Tailwind CSS&lt;/code&gt;. To create this project, run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-next-app -e with-supabase auth-with-inapp-survey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will set up your &lt;code&gt;Next.js&lt;/code&gt; project, integrating it with &lt;code&gt;Supabase-auth&lt;/code&gt; and the necessary configurations. Although &lt;code&gt;Tailwind CSS&lt;/code&gt; is included, for the purposes of this article, we don't need to use it.&lt;/p&gt;

&lt;p&gt;The advantage of creating a &lt;code&gt;Next.js&lt;/code&gt; project that comes pre-configured with &lt;code&gt;Supabase&lt;/code&gt; is that it streamlines the authentication setup for you. This includes setting up functionalities like sign-up, sign-in, log-out, and even a login page, as illustrated in the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fae1qniqnjhh5h04srl0g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fae1qniqnjhh5h04srl0g.png" alt="Supabase configured project" width="289" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pretty cool right :face_with_cowboy_hat: &lt;/p&gt;

&lt;p&gt;All you need to do is duplicate the &lt;code&gt;.env.local.example&lt;/code&gt; file within your project using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cp .env.local.example .env.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, recover your &lt;code&gt;supabase URL&lt;/code&gt; and &lt;code&gt;Anon key&lt;/code&gt; from your project's &lt;a href="https://supabase.com/dashboard/project/_/settings/api" rel="noopener noreferrer"&gt;API settings.&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEXT_PUBLIC_SUPABASE_URL=&amp;lt;your-supabase-url&amp;gt;
NEXT_PUBLIC_SUPABASE_ANON_KEY=&amp;lt;your-supabase-anon-key&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch your application, and it will start on your &lt;code&gt;localhost&lt;/code&gt; at &lt;code&gt;port 3000&lt;/code&gt;. Your home page will display the following content, and it also includes a link to the pre-configured &lt;code&gt;login&lt;/code&gt; page. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frymayoqivnhjdjogd4wx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frymayoqivnhjdjogd4wx.png" alt="Home page" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although for this tutorial I would prefer to set my &lt;code&gt;login&lt;/code&gt; page as the home page - the &lt;code&gt;index&lt;/code&gt; page. If you also share this preference, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Clear the content on the &lt;code&gt;index&lt;/code&gt; page and paste the content from the &lt;code&gt;login&lt;/code&gt; page into it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Move the &lt;code&gt;messages.tsx&lt;/code&gt; file from your &lt;code&gt;login&lt;/code&gt; folder to the &lt;code&gt;components&lt;/code&gt; folder. Once this is done, you can safely delete the &lt;code&gt;login&lt;/code&gt; folder.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;However, there are a few more adjustments required in your &lt;code&gt;auth&lt;/code&gt; files to adapt to the new route since the &lt;code&gt;login&lt;/code&gt; route now serves as the &lt;code&gt;index&lt;/code&gt; page.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the &lt;code&gt;sign-up/route.ts&lt;/code&gt;, make the following modification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Rest of your code&lt;/span&gt;
    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Rest of your code&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;requestUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?error=Could not authenticate user`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// A 301 status is required to redirect from a POST to a GET route&lt;/span&gt;
        &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;requestUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?message=Check email to continue the sign-in process`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// A 301 status is required to redirect from a POST to a GET route&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;sign-out/route.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Rest of the code&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Rest of the code&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;requestUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// A 301 status is required to redirect from a POST to a GET route&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;sign-in/route.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Rest of the code&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Rest of the code&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;requestUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?error=Could not authenticate user`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// A 301 status is required to redirect from a POST to a GET route&lt;/span&gt;
        &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;requestUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/dashboard`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// A 301 status is required to redirect from a POST to a GET route&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that in the &lt;code&gt;sign-in&lt;/code&gt; route, we redirected to the &lt;code&gt;dashboard&lt;/code&gt; page in the return statement, although we won't implement a &lt;code&gt;dashboard&lt;/code&gt; page for this tutorial. This just ensures that the user is directed to the &lt;code&gt;dashboard&lt;/code&gt; page after the &lt;code&gt;sign-in&lt;/code&gt; process is completed.&lt;/p&gt;

&lt;p&gt;Finally, in the &lt;code&gt;callback/route.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Rest of the code&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Rest of the code&lt;/span&gt;
  &lt;span class="c1"&gt;// URL to redirect to after the sign-in process completes&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;requestUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/onboarding`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a user attempts to sign-up on the app, the user will have to confirm his email. Upon successful email confirmation, the user will be automatically redirected to the URL specified in the &lt;code&gt;return&lt;/code&gt; statement of the &lt;code&gt;callback&lt;/code&gt; function which is the onboarding page.&lt;/p&gt;

&lt;p&gt;These modifications will align your authentication routes with the new setup where the &lt;code&gt;login&lt;/code&gt; page serves as the initial page.&lt;/p&gt;

&lt;p&gt;Now that we've completed these steps, let's proceed with implementing our onboarding page.&lt;/p&gt;

&lt;p&gt;To create the onboarding page, navigate to the root app directory, and follow the structure depicted below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7xkt6gcfn2wzuwwflehb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7xkt6gcfn2wzuwwflehb.png" alt="Onboarding page structure" width="275" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we move on to implement the in-app survey, it's essential to ensure that our onboarding page is protected before a user signs up. After all, what's authentication without protected routes, right? &lt;/p&gt;

&lt;p&gt;Fortunately, Supabase provides a straightforward solution for handling this with server components.&lt;/p&gt;

&lt;p&gt;Within your &lt;code&gt;page.tsx&lt;/code&gt; file for the onboarding page, insert the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;LogoutButton&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/components/LogoutButton&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createServerComponentClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@supabase/auth-helpers-nextjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cookies&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/headers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/navigation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Onboarding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServerComponentClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;cookies&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSession&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LogoutButton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, we create a new Supabase client using &lt;code&gt;createServerComponentClient&lt;/code&gt;, which takes &lt;code&gt;cookies&lt;/code&gt; as a parameter. This client is then assigned to the variable &lt;code&gt;supabase&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: We use &lt;code&gt;cookies&lt;/code&gt; to store user sessions as opposed to localStorage in server components because you can't access localStorage in server components. Kudos to Supabase for this solution! 👍 &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The subsequent code block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="p"&gt;},}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSession&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is used to check if a user session exists. If a session exists, the user can access the onboarding page without any issues. However, if the &lt;code&gt;session&lt;/code&gt; is absent, the &lt;code&gt;if&lt;/code&gt; statement will be triggered, redirecting the user back to the login page.&lt;/p&gt;

&lt;p&gt;I've also imported the &lt;code&gt;logoutButton&lt;/code&gt; component into this page in case you want to explore how the sign-in/sign-out process works.&lt;/p&gt;

&lt;p&gt;Now, let's focus on implementing our onboarding segmentation survey in the onboarding page. This way, users will encounter it right after signing up. The following section will provide a step-by-step guide on how to do this.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to implement an in-app onboarding segmentation survey with Formbricks.
&lt;/h2&gt;

&lt;p&gt;Thanks to &lt;a href="https://formbricks.com/" rel="noopener noreferrer"&gt;Formbricks&lt;/a&gt;, we do not have to build this from scratch 👏 &lt;/p&gt;

&lt;h3&gt;
  
  
  Formbricks: The only open-source solution for in-app surveys
&lt;/h3&gt;

&lt;p&gt;Formbricks is an open-source survey software that helps businesses create and send different kinds of in-app surveys. Formbricks is easy to use and integrates with any web, mobile, or desktop application. Support us by &lt;a href="https://github.com/formbricks/formbricks" rel="noopener noreferrer"&gt;giving us a star&lt;/a&gt;, it helps us build our community. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S&lt;/strong&gt;: Formbricks is offering swag for Hacktoberfest, and you also have the opportunity to win a Macbook Air! &lt;a href="https://formbricks.com/formtribe" rel="noopener noreferrer"&gt;Come and participate!&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbyb1pwkr2jf7rutpvue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbyb1pwkr2jf7rutpvue.png" alt="Hacktoberfest image" width="800" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Moving forward, here's a concise preview of the steps we're about to cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start by registering an account on the Formbricks platform.&lt;/li&gt;
&lt;li&gt;Customize your onboarding survey according to your preferences.&lt;/li&gt;
&lt;li&gt;Seamlessly integrate Formbricks into your application.&lt;/li&gt;
&lt;li&gt;Incorporate your in-app onboarding survey.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Customize your onboarding survey
&lt;/h3&gt;

&lt;p&gt;Upon creating your account on &lt;a href="https://formbricks.com" rel="noopener noreferrer"&gt;Formbricks&lt;/a&gt;, you'll be directed to your dashboard, where you'll find a variety of survey templates. For this tutorial, select the onboarding segmentation survey template as that's what we'll be using.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy8ucwr2iqz4ica01n4y1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy8ucwr2iqz4ica01n4y1.png" alt="Onboarding segmentation survey" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, you'll be taken to a page where you can edit and tailor this survey to meet your specific requirements. Here, you'll encounter three pre-customized question cards, and you have the option to add more questions if necessary.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsokwsenpdp28ybwk0m1d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsokwsenpdp28ybwk0m1d.png" alt="Customize survey" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's important to note that any modifications made to each question card are instantly reflected in the preview.&lt;/p&gt;

&lt;p&gt;Once you've completed your question editing, navigate to the "Settings" tab located adjacent to the "Questions" tab. In this section, you can configure the survey to align with your specific needs.&lt;/p&gt;

&lt;p&gt;For the "How to Ask" card, ensure that the web app option is selected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4r49w4de3ax131yk6tgr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4r49w4de3ax131yk6tgr.png" alt="How to ask" width="685" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another crucial configuration is the survey trigger. Here, you'll define how and when you want your survey to be triggered. To align with the flow of our project and display the survey whenever a user reaches the onboarding page we've implemented, we will choose to trigger the survey only when a user navigates to the onboarding page.&lt;/p&gt;

&lt;p&gt;To set up this process, begin by selecting the dropdown and choosing the "Add action" option. This action will trigger a modal to appear:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pjqqqljak7ewfcwxzhg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pjqqqljak7ewfcwxzhg.gif" alt="Modal" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Complete the fields in the modal as illustrated below. Feel free to customize these details according to your preferences:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fufftiiela3atbqul9561.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fufftiiela3atbqul9561.png" alt="Filled modal" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please note that in this step, we need to select the "Page URL" option, which allows us to specify the URL where the survey should be displayed. As shown, I've filled the URL field with &lt;code&gt;https:localhost:3000/onboarding&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once you've provided the necessary information, click the "Track Action" button and then select the option from the dropdown:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuccjb2udgl1owz21abz4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuccjb2udgl1owz21abz4.gif" alt="Dropdown" width="668" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another card to note is the "styling" card. This card enables you to style your survey to align with your UI requirements.&lt;/p&gt;

&lt;p&gt;Upon completing the setup, click the "Publish" button located at the top right corner of the page. This action will redirect you to a page displaying your survey analytics.&lt;/p&gt;

&lt;p&gt;Next, we will delve into how to establish a connection between your web app and Formbricks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting Your Web App and Formbricks
&lt;/h3&gt;

&lt;p&gt;In the settings page, navigate to the "setup checklist" tab found in the sidebar. This page contains all the necessary steps for connecting your web app to Formbricks.&lt;/p&gt;

&lt;p&gt;You'll also notice a widget status that informs you whether your app has been successfully connected or not. At this point, since it hasn't been connected, it will be displayed like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9a8uv4gymxnsvuknwb8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9a8uv4gymxnsvuknwb8.png" alt="Widget status" width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To establish the connection, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the Formbrick widget in your web application using the following command:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   npm install @formbricks/js --save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create a client component, &lt;code&gt;formbricks.tsx&lt;/code&gt;, in the root app folder, and insert the following code into it:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;formbricks&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@formbricks/js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;usePathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useSearchParams&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/navigation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;FormbricksProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;usePathname&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSearchParams&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

     &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;formbricks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
         &lt;span class="na"&gt;environmentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;environment-id&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;apiHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://app.formbricks.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// remove when in production&lt;/span&gt;
       &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

     &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;formbricks&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;registerRouteChange&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value of your &lt;code&gt;environmentId&lt;/code&gt; can be obtained from your setup checklist page. I've intentionally omitted it here as it's meant to remain private.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkyqfnqf2egxng1zmeof6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkyqfnqf2egxng1zmeof6.png" alt="EnvironmentId" width="751" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finally, in your &lt;code&gt;app/layout.tsx&lt;/code&gt; file, import the &lt;code&gt;formbricks.tsx&lt;/code&gt; file and render it as shown below:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;FormbricksProvider&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./formbricks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;
   &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormbricksProvider&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Render here */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
         &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Rest of the code here */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
         &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upon restarting your web app, the status indicator will be updated to the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffvf5ote0kckm7hzri7w0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffvf5ote0kckm7hzri7w0.png" alt="updated status" width="800" height="297"&gt;&lt;/a&gt;&lt;br&gt;
   Additionally, you'll see in your console that your app has successfully been connected to Formbricks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbrz0jbnx6dqi59viste6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbrz0jbnx6dqi59viste6.png" alt="console connection" width="524" height="385"&gt;&lt;/a&gt;&lt;br&gt;
   You can now test this by attempting to sign up for your app. When you click the sign-up button, you will receive a notification that a mail has been sent to your email address for verification.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmepvbadh5t0qp6gdosm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmepvbadh5t0qp6gdosm.png" alt="Login page" width="800" height="381"&gt;&lt;/a&gt;&lt;br&gt;
   Upon verification, you will be redirected to the 'onboarding' page as intended. There, your onboarding segmentation survey will appear just as we've implemented:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0xcv2qgqqzp6ktgua5t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0xcv2qgqqzp6ktgua5t.png" alt="Onboarding survey" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And there you have it, you've learned how straightforward it is to segment your users using Formbricks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Notes
&lt;/h2&gt;

&lt;p&gt;Throughout this article, you've gained insights into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implementing authentication and protected routes with Supabase.&lt;/li&gt;
&lt;li&gt;Integrating an onboarding segmentation survey into your web app with Formbricks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can access the code for this project &lt;a href="https://github.com/SiR-PENt/auth-with-inapp-survey" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Additionally, don't forget to support us by &lt;a href="https://github.com/formbricks/formbricks" rel="noopener noreferrer"&gt;giving us a star&lt;/a&gt; ⭐!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>hacktoberfest</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>📊🔍Measure Your Product-Market Fit With Formbricks' In-App Product-Market Fit Survey 📏📈</title>
      <dc:creator>Olasunkanmi Balogun</dc:creator>
      <pubDate>Fri, 13 Oct 2023 17:55:51 +0000</pubDate>
      <link>https://forem.com/formbricks/measure-your-product-market-fit-with-formbricks-in-app-product-market-fit-survey-aif</link>
      <guid>https://forem.com/formbricks/measure-your-product-market-fit-with-formbricks-in-app-product-market-fit-survey-aif</guid>
      <description>&lt;p&gt;By gauging your startup's product-market fit (PMF), you can determine whether your venture has successfully created a product that resonates with users' preferences and needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;In this tutorial, you'll learn how to integrate an in-app PMF survey in your &lt;code&gt;Next.js&lt;/code&gt; application with &lt;a href="https://formbricks.com" rel="noopener noreferrer"&gt;Formbricks&lt;/a&gt;. It has been built to suit your needs with best practices just like &lt;a href="https://review.firstround.com/how-superhuman-built-an-engine-to-find-product-market-fit" rel="noopener noreferrer"&gt;Superhuman.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3btdr1edpgid6d8c59ni.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3btdr1edpgid6d8c59ni.gif" alt="Time to learn GIF" width="600" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Formbricks: The Only Open-Source Solution For In-App PMF Surveys
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Formbricks&lt;/code&gt; is an open-source survey software that helps businesses create and send in-app PMF surveys. Formbricks is easy to use and integrates with any web, mobile, or desktop application. Support us by &lt;a href="https://github.com/formbricks/formbricks" rel="noopener noreferrer"&gt;giving us a star.&lt;/a&gt; 😉&lt;/p&gt;

&lt;p&gt;Now, before we delve into integrating our PMF survey into our application, let's first create a template for how our survey should appear in our app. We will create this template within the Formbricks cloud platform. &lt;/p&gt;

&lt;p&gt;Here's a brief about the steps we'll cover moving forward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Register an account on the Formbricks platform.&lt;/li&gt;
&lt;li&gt;Customize your PMF survey to suit your preferences.&lt;/li&gt;
&lt;li&gt;Seamlessly integrate Formbricks into your application.&lt;/li&gt;
&lt;li&gt;Implement your in-app PMF survey.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Create an account on the Formbricks platform - It's free
&lt;/h2&gt;

&lt;p&gt;Formbricks offers you the choice to either &lt;a href="https://formbricks.com/docs/self-hosting/deployment" rel="noopener noreferrer"&gt;self-host&lt;/a&gt; or take the simpler path by registering an account on the &lt;a href="https://app.formbricks.com/auth/login" rel="noopener noreferrer"&gt;Formbricks Cloud platform.&lt;/a&gt; For this tutorial will opt for the cloud platform. &lt;/p&gt;

&lt;p&gt;Once you have completed the signup and the onboarding procedures, you will be navigated to your dashboard.&lt;/p&gt;

&lt;p&gt;Your dashboard should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fli1jossxnze9ckamcaqe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fli1jossxnze9ckamcaqe.png" alt="Formbricks dashboard" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If everything has proceeded smoothly up to this stage, let's continue to create and customize our PMF survey 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  2. How to create and customize your PMF survey
&lt;/h2&gt;

&lt;p&gt;Within the "For you" feed, you may not come across the PMF survey card among the available templates. In such cases, simply click the "Product Experience" filter button, where you'll discover the PMF survey featuring two distinct templates: one resembling the superhuman template and the other being rather short.&lt;/p&gt;

&lt;p&gt;Choose the one that aligns best with your requirements. However, for the sake of this article, I'll opt for the superhuman template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6g5dolt5iolmrou8akln.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6g5dolt5iolmrou8akln.png" alt="Product experience description" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, on selecting the one with the superhuman template, you'll be navigated to a page that contains six different question cards (you can choose to add more if you like), and a Thank you card which will be displayed at the end of the survey.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdljn3712hv5x1wvscw3n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdljn3712hv5x1wvscw3n.png" alt="Question cards image" width="800" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also choose to edit each of the questions if you like by clicking on whichever question card you want to edit. It's worth noting that you changes is reflected in the preview real-time.&lt;/p&gt;

&lt;p&gt;As an example, in the second question card, you can choose the next question to be displayed based on which answer was submitted with the logic jumps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpra42fldzz8m1y7oh9yu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpra42fldzz8m1y7oh9yu.png" alt="Logic jump image" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above image, I have modified my logic to skip to the fourth question card if the "Not at all disappointed" option was selected in the survey instead of normally navigating to the third question. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1i39r876o7dmelqgn6h.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1i39r876o7dmelqgn6h.gif" alt="illustration for logic jump" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you've completed modifying your questions, navigate to the Settings tab, located right next to the Questions tab. In this section, you can configure your survey according to your preferences.&lt;/p&gt;

&lt;p&gt;For the "How to Ask" segment, select the web app choice, since our intention is to integrate it into a web application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8n84ekx7ewoguzm4nig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8n84ekx7ewoguzm4nig.png" alt="Web app illustration" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You may get a note in orange that hints you haven't connected with our app yet. It looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffpxvfzzwhd5afj5ypeps.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffpxvfzzwhd5afj5ypeps.png" alt="Orange note image" width="718" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I didn't encounter this notification because I had previously connected Formbricks to an application. However, no need to worry! I'll guide you through overcoming this issue in a subsequent section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, moving on to the Survey Trigger section, this is where you'll configure how you'd like your survey to be triggered in your app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo5pv2prkyk0cj9eeh5ad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo5pv2prkyk0cj9eeh5ad.png" alt="Survey trigger illustration" width="676" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can select however you want to trigger your survey in your app when you click the select field.&lt;/p&gt;

&lt;p&gt;Perhaps you want to trigger the survey when a user visits a particular URL, this option isn't available in the dropdown. Instead click the "Add Action" option, this will pop-up a modal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6tumd6epnrkssk4jfag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6tumd6epnrkssk4jfag.png" alt="Survey trigger modal" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above dropdown, I have filled up the required fields to achieve our aim to trigger the survey when a user visits a particular URL. &lt;/p&gt;

&lt;p&gt;Regarding the URL for displaying the survey within our app, I've configured the condition to trigger when the browser's URL contains &lt;code&gt;https://localhost:3000/dashboard&lt;/code&gt;. This is based on the fact that I'll be using my development server, which initiates on &lt;code&gt;localhost:3000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, feel free to select any URL of your preference. Just keep in mind that using an invalid URL will result in an error message stating "your survey will not be shown."&lt;/p&gt;

&lt;p&gt;When you are done, click the &lt;code&gt;Track Action&lt;/code&gt; button, the action should now be available in the dropdown. Click the dropdown again to select it. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1gmknl4vn79qzj3wa8du.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1gmknl4vn79qzj3wa8du.png" alt="Visit dashboard present" width="659" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you hit the publish button at the top right corner, you will be navigated to your PMF survey dashboard. Here, you'll be notified that you have not connected Formbricks to your app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fka5x8gzz2jj8lzhnuplp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fka5x8gzz2jj8lzhnuplp.png" alt="PMF survey dashboard" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hit the connect button, this will direct you to the Setup checklist page.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Setup Checklist: Integrate Formbricks Widget Into Your Application
&lt;/h2&gt;

&lt;p&gt;Since we haven't connected our application to Formbricks Cloud, the widget status indicator will display on your screen like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxuinz8kcxxo94541bvdx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxuinz8kcxxo94541bvdx.png" alt="Setup checklist status" width="800" height="296"&gt;&lt;/a&gt;_&lt;/p&gt;

&lt;p&gt;To connect our app with the cloud, we'll have to dive into our code editor 🚀&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To streamline this section, I'll assume that your Next.js application is already up and running, allowing us to get straight to the specifics.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To start, install the Formbricks package into our app with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @formbricks/js --save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, navigate to the &lt;code&gt;_app.js&lt;/code&gt; file and paste the following code in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;formbricks&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@formbricks/js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/router&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;formbricks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;environmentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;your environment id&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;apiHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://app.formbricks.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Connect next.js router to Formbricks&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleRouteChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formbricks&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;registerRouteChange&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;routeChangeComplete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleRouteChange&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;routeChangeComplete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleRouteChange&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;environmentId&lt;/code&gt; property has been intentionally omitted in the &lt;code&gt;if&lt;/code&gt; statement. In actual practice, this value is private and unique to each user. You can retrieve your &lt;code&gt;environmentId&lt;/code&gt; from &lt;strong&gt;Step 2&lt;/strong&gt; of the setup checklist page. Copy and paste the value into the appropriate variable as seen in the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcs67ztwongdmge1jdzed.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcs67ztwongdmge1jdzed.png" alt="Set up checklist image" width="751" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having done this, the widget status indicator should have been updated to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftuj177tas8mdjany1ela.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftuj177tas8mdjany1ela.png" alt="Widget status indicator" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, you should see that your PMF survey has been fetched in your browser's console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbeelhm9vmmtb7k2zqkuf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbeelhm9vmmtb7k2zqkuf.png" alt="Image of the console" width="501" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If everything works well to this point, let's go ahead to trigger the PMF survey in our app.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Trigger Your In-app PMF Survey
&lt;/h2&gt;

&lt;p&gt;I'll navigate to the &lt;code&gt;dashboard&lt;/code&gt; page from my app's index page. Hence, I'll implement a link to the &lt;code&gt;dashboard&lt;/code&gt; page in my index page as seen below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Formbricks PMF Survey&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Generated by create next app"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* link to dashboard */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/dashboard"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Nav To Dashboard&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I click on the &lt;code&gt;link&lt;/code&gt;, the page navigates to the dashboard and triggers the survey according to how we implemented the trigger on the Formbricks platform:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwm8ung4jd17v9erjfgbl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwm8ung4jd17v9erjfgbl.gif" alt="Illustration of survey trigger" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And there you have it, you have successfully implemented your in-app PMF survey.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ed9dqwtw97zl2iw9cep.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ed9dqwtw97zl2iw9cep.gif" alt="Happy gif" width="640" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you desire a more personalized survey, maybe to harmonize with the colors in your UI, we offer a solution for this in the "Look and Feel" section of the settings page. Feel free to dive in and tailor the survey to your liking 🎨 &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So far, you learned how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;connect Formbricks Cloud to your app&lt;/li&gt;
&lt;li&gt;create a PMF with the best template possible (superhuman) &lt;/li&gt;
&lt;li&gt;utilize Formbricks to seamlessly integrate an in-app PMF survey &lt;/li&gt;
&lt;li&gt;Customize your survey to your taste&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this solution, you are just on the right track to measure your PMF in no time. 🚀 👊 &lt;/p&gt;

&lt;p&gt;To help us keep this articles coming, don't forget to give us a star on &lt;a href="https://github.com/formbricks/formbricks" rel="noopener noreferrer"&gt;Github&lt;/a&gt;. 😉&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>product</category>
    </item>
    <item>
      <title>🔥 How To Get Juicy User Insights With In-App Pre-Churn Survey In Next.js With Formbricks 💡💬</title>
      <dc:creator>Olasunkanmi Balogun</dc:creator>
      <pubDate>Fri, 22 Sep 2023 12:03:34 +0000</pubDate>
      <link>https://forem.com/formbricks/how-to-get-juicy-user-insights-with-in-app-pre-churn-survey-in-nextjs-with-formbricks-1536</link>
      <guid>https://forem.com/formbricks/how-to-get-juicy-user-insights-with-in-app-pre-churn-survey-in-nextjs-with-formbricks-1536</guid>
      <description>&lt;p&gt;Churn surveys are a valuable tool for businesses, especially app-based businesses, to understand why customers are leaving their service. By asking customers why they are churning, businesses can identify areas where they can improve their product or service to prevent future churn. An example of such surveys can be seen below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foayajb59v8han1jakfot.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foayajb59v8han1jakfot.jpg" alt="Image of a churn survey" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine being able to anticipate user departures before they happen, giving you a chance to address concerns, tailor your offerings, and ultimately, boost user loyalty. This is where the power of pre-churn surveys comes into play, revolutionizing the way businesses interact with their users.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;In this article, you will learn how to get juicy user insights with in-app pre-churn surveys in your &lt;code&gt;Next.js&lt;/code&gt; application using &lt;a href="https://formbricks.com/" rel="noopener noreferrer"&gt;&lt;code&gt;Formbricks&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvsftf09407cdbv3xy4uj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvsftf09407cdbv3xy4uj.gif" alt="Light bulb gif" width="450" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Formbricks: The Only Open-Source Solution For Pre-Churn Surveys
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Formbricks&lt;/code&gt; is an open-source survey software that can help businesses create and send in-app pre-churn surveys. Formbricks is easy to use and integrates with any web, mobile, or desktop application. Support us by &lt;a href="https://github.com/formbricks/formbricks" rel="noopener noreferrer"&gt;giving us a star.&lt;/a&gt; 😉 &lt;/p&gt;

&lt;h2&gt;
  
  
  How To Craft A Churn Survey With Formbricks
&lt;/h2&gt;

&lt;p&gt;In this section, I will guide you systematically through the process of crafting a churn survey for your application. Here's an overview of the steps we'll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a complimentary Formbricks cloud account.&lt;/li&gt;
&lt;li&gt;Construct your churn survey utilizing the Formbricks platform.&lt;/li&gt;
&lt;li&gt;Seamlessly integrate Formbricks into your application.&lt;/li&gt;
&lt;li&gt;Put theory into practice by implementing your in-app survey.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1. Create an account on Formbricks - It's Free
&lt;/h3&gt;

&lt;p&gt;When utilizing Formbricks, you have the flexibility to either opt for &lt;a href="https://formbricks.com/docs/self-hosting/deployment" rel="noopener noreferrer"&gt;self-hosting&lt;/a&gt; if you prefer, or take the more straightforward path by registering on our &lt;a href="https://app.formbricks.com/auth/login" rel="noopener noreferrer"&gt;platform&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Upon completing the signup process and swiftly navigating through the onboarding procedures, you will find yourself on your dashboard, which will be presented in a layout similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnueb10htocgl4rpr9xsh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnueb10htocgl4rpr9xsh.png" alt="Formbricks dashboard image" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Following this, it's time to construct your churn survey 🛠️&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Craft your churn survey
&lt;/h3&gt;

&lt;p&gt;Navigate to your dashboard and select the churn survey template:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftcmqyrm4mavgellko6su.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftcmqyrm4mavgellko6su.png" alt="Churn survey tab image" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll be navigated to a page that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsk4g8dksp00bh8tmmq2t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsk4g8dksp00bh8tmmq2t.png" alt="Churn Survey page" width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is your canvas for refining survey questions. Keep in mind that your edits on the left side reflect in real-time in the preview.&lt;/p&gt;

&lt;p&gt;Once you've refined the questions to your liking, proceed to the &lt;code&gt;Settings&lt;/code&gt; tab adjacent to the &lt;code&gt;Questions&lt;/code&gt; tab. This is where you can fine-tune your survey's configuration.&lt;/p&gt;

&lt;p&gt;For the "How to Ask" segment, opt for the web app choice, given your intention to integrate it into your web application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonrp0l73s310csz1jgsh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonrp0l73s310csz1jgsh.png" alt="How to ask section" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's a note in orange that hints we haven't connected with our app yet. No sweat! We'll get back to it, let's get our other survey configuration right first!&lt;/p&gt;

&lt;p&gt;Another essential aspect within the &lt;code&gt;Settings&lt;/code&gt; tab is the &lt;code&gt;Survey Trigger&lt;/code&gt; section. As its name implies, this settings is for what will trigger the survey in your app. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqaq189m60791yhqo4hyb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqaq189m60791yhqo4hyb.png" alt="Survey trigger section image" width="676" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you click on the select field, a dropdown will appear, presenting you with a range of options. In case none of these options align with your preferences, you can introduce a personalized trigger by selecting the "Add action" choice. This will prompt a modal to appear:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fag1k88fpewwdu0n8kk0r.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fag1k88fpewwdu0n8kk0r.gif" alt="Illustration to select out-of-the-box options" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the available options, feel free to make your selection. However, for the context of this article, I'll demonstrate using the inner text option.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6zx2egk7ubxyl6nijln.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6zx2egk7ubxyl6nijln.png" alt="Inner text option" width="673" height="647"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you've chosen your preference within this modal, proceed to save your choice by clicking the "Track Action" button. Subsequently, revisit the dropdown and select the newly added option.&lt;/p&gt;

&lt;p&gt;Now, proceed to click the "Publish" button located in the upper right corner.&lt;/p&gt;

&lt;p&gt;This action will direct you to the Summary page, where you'll gain access to your survey analytics. Additionally, you'll receive a prompt to install the Formbricks widget, enabling you to establish a connection between your survey and your application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc00b65f39reh9t9ehgi4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc00b65f39reh9t9ehgi4.png" alt="Survey analytics image" width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on it to navigate to the setup checklist page. &lt;/p&gt;

&lt;h3&gt;
  
  
  3. Setup Checklist: Installing The Formbricks Widget
&lt;/h3&gt;

&lt;p&gt;On the setup checklist page, you'll come across a widget status indicator. This indicator informs us whether our application has been linked to Formbricks Cloud or not. Since we haven't yet established the connection at this juncture, you will observe the following display on your screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpd7cen8vq9vfusg3cza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpd7cen8vq9vfusg3cza.png" alt="Status indicator image " width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the point where we'll have to get our hands dirty and dive into our app code editor. 😃 🚀 &lt;/p&gt;

&lt;p&gt;I assume you already have your Next.js application up and running, so we're set to hit the ground running! &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: I'll be using the Next.js pages dir moving forward.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We'll start by installing Formbricks accross our app with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @formbricks/js --save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Afterwards, navigate to the &lt;code&gt;_app.js&lt;/code&gt; component and modify the code as seen below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;formbricks&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@formbricks/js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/router&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;formbricks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;environmentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;your environment id&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;apiHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://app.formbricks.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Connect next.js router to Formbricks&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleRouteChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formbricks&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;registerRouteChange&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;routeChangeComplete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleRouteChange&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;routeChangeComplete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleRouteChange&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pay attention to the &lt;code&gt;if&lt;/code&gt; statement before the component definition. It makes sure that the widget is only initialized if this component is rendered in a browser.&lt;/p&gt;

&lt;p&gt;For this tutorial's sake, the &lt;code&gt;environmentId&lt;/code&gt; property has been intentionally omitted. In actual practice, this value is private and unique to each user. You can retrieve your &lt;code&gt;environmentId&lt;/code&gt; from &lt;strong&gt;Step 2&lt;/strong&gt; of the setup checklist page. Copy and paste the value into the appropriate variable as depicted below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4mq8q9pdiyfch45lqc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4mq8q9pdiyfch45lqc6.png" alt="Environmentid image" width="751" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Following this, the widget status indicator in the Setup checklist page should have been updated to this after reloading your app 🎉:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58rskcr8w7noxi9si6n0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58rskcr8w7noxi9si6n0.png" alt="Status indicator update" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your web browser's console should also display the following logs, confirming the establishment of the connection:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fif6tot0oqjf3e6witkhl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fif6tot0oqjf3e6witkhl.png" alt="Console log image" width="511" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we've verified the connection between your app and Formbricks Cloud, we can proceed to implement the survey trigger.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. How to trigger the Formbricks pre-churn survey
&lt;/h3&gt;

&lt;p&gt;As a quick reminder, we configured a trigger based on the button's inner text, "Cancel Subscription."&lt;/p&gt;

&lt;p&gt;With that in mind, feel free to incorporate the &lt;code&gt;button&lt;/code&gt; with the designated inner text wherever you see fit. I'll demonstrate the implementation in my &lt;code&gt;index.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Formbricks Churn Survey&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Generated by create next app"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* survey trigger */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Cancel Subscription&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On my home page, the survey can now be triggered after clicking the button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82mbwtomyh7ip1r1khty.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82mbwtomyh7ip1r1khty.gif" alt="Illustration of survey trigger" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations! You have effectively integrated your churn survey into your app! 🎉 &lt;/p&gt;

&lt;p&gt;Furthermore, you have the flexibility to customize the placement and appearance of the survey in your application. To achieve this, navigate to the settings page within your Formbricks account and select the "Look &amp;amp; Feel" option from the sidebar.&lt;/p&gt;

&lt;p&gt;As an illustration, if you prefer your survey to appear at the center of your web application, scroll down to the "In-app survey placement" section and opt for the "Centered Modal" choice. After adjusting it to your liking, the modal should now appear like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0347az3n16yzvq20xfp4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0347az3n16yzvq20xfp4.gif" alt="Illustration for centered modal option" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the placement doesn't reflect immediately, try restarting your app. 😉 &lt;/p&gt;

&lt;p&gt;Finally, you can effortlessly access your survey analytics and view responses on the Formbricks platform. Simply click on the survey you've crafted to explore these valuable insights.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So far, you've learnt how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;connect Formbricks Cloud to your app&lt;/li&gt;
&lt;li&gt;Easily create an in-app Churn Survey with Formbricks&lt;/li&gt;
&lt;li&gt;How to view your survey analytics on Formbricks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From now on, the world of in-app pre-churn survey is yours. Go ahead and prevent that churn 💪 😁 &lt;/p&gt;

&lt;p&gt;To help us keep this articles coming, kindly give us a star on &lt;a href="https://github.com/formbricks/formbricks" rel="noopener noreferrer"&gt;Github.&lt;/a&gt; 😉 &lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>💻 A Technical Interview Project: Building a Lending-as-a-Service Application 🏦</title>
      <dc:creator>Olasunkanmi Balogun</dc:creator>
      <pubDate>Thu, 29 Jun 2023 17:40:56 +0000</pubDate>
      <link>https://forem.com/sukodes/-a-technical-interview-project-building-a-lending-as-a-service-application-3k8c</link>
      <guid>https://forem.com/sukodes/-a-technical-interview-project-building-a-lending-as-a-service-application-3k8c</guid>
      <description>&lt;p&gt;I recently completed a technical interview with a lending-as-a-service company. The interview required me to build four pages with TypeScript, React, and SCSS for styling. &lt;/p&gt;

&lt;p&gt;Although, unfortunately I didn't obtain the position, but since it's a large project (which I personally think is gross for the first stage of a technical interview) I'm committed to sharing what I learned. In this article, I'll walk you through the features I implemented and how I implemented them. I hope this article will be helpful to other frontend developers who are preparing for technical interviews.&lt;/p&gt;

&lt;p&gt;PS: I'm still open for a frontend developer role. If you're hiring for a frontend role, please reach out to me. I'd love to learn more about the opportunity.&lt;/p&gt;

&lt;p&gt;Note that, this article will focus on the features implemented, with little to no discussion of the styling.&lt;/p&gt;

&lt;h1&gt;
  
  
  TL;DR
&lt;/h1&gt;

&lt;p&gt;The following is a brief overview of the pages and features implemented in the project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Login page: I used Firebase for authentication and implemented protected routes with React Router, even though it wasn't required.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;List of users page: This page pulls data from a mock API with 500 records using Axios and Axios Interceptors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;User details page: This page was required to use local storage or indexedDB to store and retrieve user details. I chose to use localStorage.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The end product of the pages implemented should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9gohyiz7ue3wywyfmdwu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9gohyiz7ue3wywyfmdwu.png" alt="Log In Page" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F962q6erdhrm3zcx7rcru.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F962q6erdhrm3zcx7rcru.png" alt="Dashboard Page" width="800" height="768"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1i52hadpszrjtbekgnq6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1i52hadpszrjtbekgnq6.png" alt="User Details Page" width="800" height="885"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article shall be a complete overhaul from the ground up, with no stone unturned. I will start with the login page, and discuss how the user is navigated to the dashboard. From there, I will also explore the features implemented in the users page, and finally, we shall reach the user details page, where the user journey ends.&lt;/p&gt;

&lt;p&gt;When you are ready, let's dive in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqebwenmod4e4te7l832d.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqebwenmod4e4te7l832d.gif" alt="Ready GIF" width="640" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Set My Project Up
&lt;/h2&gt;

&lt;h3&gt;
  
  
  I Set Up My React + TypeScript Project With Vite
&lt;/h3&gt;

&lt;p&gt;To kickstart my project swiftly, I opted for &lt;a href="https://vitejs.dev/guide/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt; as my project initializer, and I highly recommend you do the same if you haven't been using Vite. Initializing a TypeScript + React project with Vite is effortless with just one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm create vite@latest interview-project -- --template react-ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How I Set Up Firebase For Authentication
&lt;/h3&gt;

&lt;p&gt;I decided to utilize Firebase for authentication for this app although it wasn't a requirement. &lt;/p&gt;

&lt;p&gt;The fact that I also wanted to implement a protected route functionality for all authenticated pages also played a role in my decision. This feature will be discussed in a later section.&lt;/p&gt;

&lt;p&gt;In this section, I will briefly guide you through the process of how I set it up.&lt;/p&gt;

&lt;p&gt;Generally, to use Firebase, you need to &lt;a href="https://firebase.google.com/docs/web/setup" rel="noopener noreferrer"&gt;create and register&lt;/a&gt; your project on the platform, which I did. &lt;/p&gt;

&lt;p&gt;Following this, I installed Firebase in my project and created a &lt;code&gt;components&lt;/code&gt; folder. Inside this folder, I created a file named &lt;code&gt;firebaseConfig.ts&lt;/code&gt; to store my configuration details and establish a connection between my app and Firebase like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initializeApp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firebase/app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getAuth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firebase/auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebaseConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//firebase config&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize Firebase&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firebaseConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="c1"&gt;// connect firebase&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are new to Firebase and are interested in learning more about it, check out the official documentation &lt;a href="https://firebase.console.com" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  File Structure
&lt;/h3&gt;

&lt;p&gt;I established a &lt;code&gt;pages&lt;/code&gt; directory to contain the various pages of the application.&lt;/p&gt;

&lt;p&gt;Within the previously created &lt;code&gt;components&lt;/code&gt; directory, I created subdirectories with names corresponding to the folders within the &lt;code&gt;pages&lt;/code&gt; directory. This organizational structure allows for convenient grouping of relevant components within each page-specific folder.&lt;/p&gt;

&lt;p&gt;Furthermore, I added a &lt;code&gt;styles&lt;/code&gt; folder in the &lt;code&gt;src&lt;/code&gt; directory to centralize all the styles for my pages. Additionally, an &lt;code&gt;utils&lt;/code&gt; folder was created within the &lt;code&gt;src&lt;/code&gt; directory to store files responsible for handling API requests.&lt;/p&gt;

&lt;p&gt;I had adopted this file structure during my time at my previous job.&lt;/p&gt;

&lt;p&gt;In the end, the folder structure looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- project
  - src
    - components    
      - dashboard
      - common
      - user-details
      - users     
      - login
      - firebaseConfig.ts
    - pages
      - Login.tsx
      - Users.tsx
      - User-details.tsx
    - styles
    - utils
      - request-adapter.ts
      - requests.ts
    - main.tsx
  - public
  - package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'll now walk you through each page and files if necessary in the next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Page Routing In The &lt;code&gt;main.tsx&lt;/code&gt; File
&lt;/h3&gt;

&lt;p&gt;The powerful React Router was employed for seamless page routing, not like there are numerous alternatives available lol. If you are new to React Router or uncertain about its benefits, I recommend checking out its documentation &lt;a href="https://reactrouter.com/en/main/start/overview" rel="noopener noreferrer"&gt;here&lt;/a&gt; for further insights. &lt;/p&gt;

&lt;p&gt;Once React Router is installed, I implemented the routes in the &lt;code&gt;main.tsx&lt;/code&gt; file as seen in the code snippet below. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I had not used React Router in a while due to the fact that I have been writing a lot of &lt;code&gt;Nextjs&lt;/code&gt; these days. As a result, I was taken aback by the new syntax when revisiting it. If you're in a similar situation where you haven't kept up with the updates, note that an updated version, &lt;code&gt;6.4&lt;/code&gt;, has been released with fresh syntax and features. I recommend referring to the documentation to stay updated and informed.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;createBrowserRouter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;RouterProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Login&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/Login-Auth.tsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Users&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/Users.tsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;UserDetails&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/User-details.tsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createBrowserRouter&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;

  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Login&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/dashboard/users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/dashboard/users/:id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserDetails&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RouterProvider&lt;/span&gt; &lt;span class="na"&gt;router&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How I Implemented Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Starting Off With Authentication In The Log In Page 🚀
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkw16fudpac2x8v3ocw7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkw16fudpac2x8v3ocw7.png" alt="Log In Page" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the sign-in method, Firebase enables you to use different sign-in providers, ranging from &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; provider to &lt;code&gt;Google&lt;/code&gt; provider and so on... For the authentication of this app, I employed the email and password provider since the email and password input fields were provided and required.&lt;/p&gt;

&lt;p&gt;Here's how I implemented the feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createUserWithEmailAndPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signInWithEmailAndPassword&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firebase/auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="nx"&gt;useNavigate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/login-auth/firebaseConfig&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;navigate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useNavigate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEmail&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPassword&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;signUp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSignUp&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;helperText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setHelperText&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setHide&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSignUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FormEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLButtonElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;createUserWithEmailAndPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setHelperText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Congrats!, you can now Sign In&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setHelperText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;setSignUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;signUp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;})&lt;/span&gt; 
   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSignIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FormEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLButtonElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;signInWithEmailAndPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/dashboard/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
     &lt;span class="p"&gt;})&lt;/span&gt;
   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorCode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth/user-not-found!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
    &lt;span class="nf"&gt;setHelperText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email is not registered!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;setHelperText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setHelperText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Welcome&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Enter&lt;/span&gt; &lt;span class="nx"&gt;details&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;signUp&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sign up&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;  &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;helperText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Input&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Input&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hide&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setPassword&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setHide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hide&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Show&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hide&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Forgot&lt;/span&gt; &lt;span class="nx"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Don&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;t have an account? &amp;lt;span onClick={() =&amp;gt; setSignUp(!signUp)}&amp;gt;Sign Up&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
               &amp;lt;button type=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; onClick={!signUp ? handleSignUp : handleSignIn}&amp;gt;           
                 signUp ? &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;Log&lt;/span&gt; &lt;span class="nx"&gt;In&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; : &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;Sign&lt;/span&gt; &lt;span class="nx"&gt;Up&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;
               &amp;lt;/button&amp;gt;
            &amp;lt;/div&amp;gt;
          &amp;lt;/form&amp;gt;
)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I implemented two functions in the code block above: &lt;code&gt;handleSignIn&lt;/code&gt; and &lt;code&gt;handleSignUp&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;As their names imply, the &lt;code&gt;handleSignin&lt;/code&gt; function handles the sign in process, while the latter handles that of the sign up. If the requirements of each function are met, the code in their &lt;code&gt;.then&lt;/code&gt; block runs, if not, the error is caught in the &lt;code&gt;.catch&lt;/code&gt; block.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that once the code in the &lt;code&gt;.then&lt;/code&gt; block in the &lt;code&gt;handleSignIn&lt;/code&gt; function runs, an &lt;code&gt;auth&lt;/code&gt; object is saved in the &lt;code&gt;sessionStorage&lt;/code&gt; of the browser. This will be used when implementing the protected routes feature. More details on this in the authenticated pages section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I introduced the &lt;code&gt;signUp&lt;/code&gt; state to regulate which of the functions executes in the proper scenario. When a user hits the &lt;code&gt;sign up&lt;/code&gt; text in the form beneath the &lt;code&gt;Forgot Password&lt;/code&gt; text, the &lt;code&gt;signUp&lt;/code&gt; state is updated. The highlighted code below demonstrates how this is done:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Don't have an account? &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setSignUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;signUp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Sign Up&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As I mentioned in earlier, this state is used to toggle the functions that get invoked when the &lt;code&gt;button&lt;/code&gt; in the &lt;code&gt;form&lt;/code&gt; element is clicked. That is, if a user is new and just wants to sign up, the &lt;code&gt;handleSignUp&lt;/code&gt; function is triggered, otherwise, if it is an already existing user who wants to log in, the log in function is triggered. &lt;/p&gt;

&lt;p&gt;This also controls the text that renders in the &lt;code&gt;button&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;You can see how this is implemented in the highlighted code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;   &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'submit'&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;signUp&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;handleSignUp&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;handleSignIn&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;           
                 signUp ? ' Log In' : ' Sign Up'
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The purpose of the &lt;code&gt;signUp&lt;/code&gt; state wasn't limited to just the function and text of the button as it also updates the text below the &lt;strong&gt;&lt;code&gt;Welcome&lt;/code&gt;&lt;/strong&gt; header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Enter details to &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;signUp&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sign up&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See video below for an illustration of this scenario.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6c5z7b76ct4v9ufe1qob.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6c5z7b76ct4v9ufe1qob.gif" alt="gif illustration of text renders" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  On To The Authenticated Pages 🚶
&lt;/h3&gt;

&lt;p&gt;Before I started off with the authenticated pages - the user and the user-details page; I thought the implementation of the protected routes feature seemed to make sense after the authentication procedure was finished.&lt;/p&gt;

&lt;p&gt;As mentioned earlier, upon successful sign-in, an &lt;code&gt;auth&lt;/code&gt; object is stored in the user's browser &lt;code&gt;sessionStorage&lt;/code&gt; temporarily. I chose &lt;code&gt;sessionStorage&lt;/code&gt; for this purpose because it retains data only for the duration of the session, deleting it when the browser is closed.&lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;auth&lt;/code&gt; variable now appropriately stored in &lt;code&gt;sessionStorage&lt;/code&gt;, I proceeded to implement the protected route feature. To accomplish this, I created a Page.tsx file within the common folder of the dashboard, as indicated in the file structure section, and implemented the feature as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Navbar&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Navbar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Sidebar&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Sidebar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Navigate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PageProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;PageProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authFromSessionStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;  
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;authFromSessionStorage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; 
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Navigate&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'/'&lt;/span&gt; &lt;span class="na"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Navbar&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Sidebar&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; // navigate to log in page if user isn't authenticated
        &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since the &lt;code&gt;Page&lt;/code&gt; component will wrap around all authenticated pages, which share the navbar and sidebar components, I decided to include those components within it. This explains their inclusion in the code block. Here's an example of how I wrapped this component around an authenticated page component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// users.tsx&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      // rest of the page content here
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Following this implementation, when an unauthenticated user attempts to access an authenticated page, they will be redirected to the sign-in page to authenticate themselves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Navigating To The Users' Page 👥
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxfgfsh3f2cp1jt7of7f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxfgfsh3f2cp1jt7of7f.png" alt="Users page" width="800" height="768"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This page requires candidates to pull data from a mock API and populate it in form of a table as seen in the image above. &lt;/p&gt;

&lt;p&gt;After pulling the data, candidates are to also implement a feature to paginate the data gotten from the API just below the table:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbhy0qlfoo6ww02qu4kgu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbhy0qlfoo6ww02qu4kgu.jpg" alt="Dashboard footer" width="800" height="79"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since the number of users gotten from this API is 100, I decided to paginate the data in multiples of 20, 50, and 100. At the end the feature looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8z9rtn90pul1d2njnila.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8z9rtn90pul1d2njnila.gif" alt="gif dropdown ilustration" width="800" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Moving on, in the &lt;code&gt;request-adapter.ts&lt;/code&gt; file created in the &lt;code&gt;utils&lt;/code&gt; folder ( see folder structure section ),  I created an instance of &lt;code&gt;Axios&lt;/code&gt; with &lt;code&gt;Axios.create&lt;/code&gt; and assigned it to a variable &lt;code&gt;request&lt;/code&gt;. This instance also includes a &lt;code&gt;base URL&lt;/code&gt; and timeout configuration. I also added a response interceptor to handle successful responses and errors, finally the instance is exported for use in other parts of the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://6270020422c706a0ae70b72c.mockapi.io/lendsqr/api/v1/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interceptors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Following this, the &lt;code&gt;request&lt;/code&gt; variable is imported from the &lt;code&gt;request-adapter&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;Then, a &lt;code&gt;getUsers&lt;/code&gt; function which it uses the &lt;code&gt;request&lt;/code&gt; instance to make a GET request to the &lt;code&gt;/users&lt;/code&gt; endpoint is defined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./request-adapter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By calling the &lt;code&gt;getUsers&lt;/code&gt;, the Axios instance will send a GET request to the complete URL formed by combining the base URL from the instance's configuration and the &lt;code&gt;/users&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;getUsers&lt;/code&gt; function is exported, making it available for other modules to import and use. This function can now be called in the users' page where it will initiate a GET request to retrieve the users' data from the specified endpoint.&lt;/p&gt;

&lt;p&gt;Next, I implemented the markup for the table that displays the users. I created a &lt;code&gt;Table.tsx&lt;/code&gt; file in the users folder situated in the components folder for this purpose.&lt;/p&gt;

&lt;p&gt;Here's how the markup looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TableProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// users is a generic of type object just as in he Users component&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Table&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;TableProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
             &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Organization&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
             &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Username&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 

            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;    
           &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Email&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
           &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
             &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Phone Number&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 

             &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
             &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Date Joined&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
             &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
             &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
             &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Status&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;    
             &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
         // list of users will be here
         &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the custom type &lt;code&gt;TableProp&lt;/code&gt; defined. This type is a generic type whose parameter extends an &lt;code&gt;object&lt;/code&gt; and assigned to the users property, this ensures that the users property accepts any type of &lt;code&gt;object&lt;/code&gt;. After the users endpoint is called, the body of the table will be implemented and populated. &lt;/p&gt;

&lt;p&gt;After implementing the &lt;code&gt;Table&lt;/code&gt; component, I created another component in the &lt;code&gt;users&lt;/code&gt; folder for the pagination feature just below the table and named it &lt;code&gt;PaginatedItems.tsx&lt;/code&gt;. The pagination feature was not just implemented in this component though, I also made the call to the &lt;code&gt;users&lt;/code&gt; endpoint and rendered the &lt;code&gt;Table&lt;/code&gt; component inside this component. I will explain why.&lt;/p&gt;

&lt;p&gt;This was done mostly because I used &lt;code&gt;react-paginate&lt;/code&gt; library to implement the pagination feature. This library needs to have access with the data you want to paginate directly - the users data gotten from the API, in order to interact with it. &lt;/p&gt;

&lt;p&gt;I'll now walk you through the pagination and Table implementation step-by-step.&lt;/p&gt;

&lt;p&gt;Firstly, I defined the component and fetched the data from the API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getUsers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../../utils/requests&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AxiosResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PaginatedItems&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUsers&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AxiosResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="nf"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

    &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="c1"&gt;// code markup here&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I then went on to develop the pagination feature after implementing and obtaining the component. The npm website's instruction of how to use the &lt;code&gt;react-paginate&lt;/code&gt; module was sufficient for its integration. The following code snippet was included in the component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getUsers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../../utils/requests&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AxiosResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DropdownProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="na"&gt;setItemsPerPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Dispatch&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SetStateAction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;DropdownFilter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;setItemsPerPage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DropdownProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setItemsPerPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;20&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;   
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setItemsPerPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;50&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;   
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setItemsPerPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;100&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;   
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PaginatedItems&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;currentItems&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCurrentItems&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;itemsPerPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setItemsPerPage&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;pageCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPageCount&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;itemOffset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setItemOffset&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;endOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;itemOffset&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;itemsPerPage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nf"&gt;setCurrentItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;itemOffset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;endOffset&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
          &lt;span class="nf"&gt;setPageCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;itemsPerPage&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;itemOffset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;itemsPerPage&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="c1"&gt;// Invoke when user clicks to request another page.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handlePageClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;selected&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//since we just need the selected property&lt;/span&gt;
     &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentItems&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;itemsPerPage&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="nf"&gt;setItemOffset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newOffset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt; &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currentItems&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Showing&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; 
            &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setShowDropdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;showDropdown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
             &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;itemsPerPage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
             &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'dropdown icon'&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
             &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DropdownFilter&lt;/span&gt; 
             &lt;span class="na"&gt;setItemsPerPage&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setItemsPerPage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
             &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;showDropdown&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;out of &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

           &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ReactPaginate&lt;/span&gt;
            &lt;span class="na"&gt;nextLabel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;onPageChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handlePageClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;pageRangeDisplayed&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;marginPagesDisplayed&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;pageCount&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pageCount&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;previousLabel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;pageClassName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"page-item"&lt;/span&gt;
            &lt;span class="na"&gt;pageLinkClassName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"page-link"&lt;/span&gt;
            &lt;span class="na"&gt;previousClassName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"page-item"&lt;/span&gt;
            &lt;span class="na"&gt;previousLinkClassName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"page-link"&lt;/span&gt;
            &lt;span class="na"&gt;nextClassName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"page-item"&lt;/span&gt;
            &lt;span class="na"&gt;nextLinkClassName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"page-link"&lt;/span&gt;
            &lt;span class="na"&gt;breakLabel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;
            &lt;span class="na"&gt;breakClassName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"page-item"&lt;/span&gt;
            &lt;span class="na"&gt;breakLinkClassName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"page-link"&lt;/span&gt;
            &lt;span class="na"&gt;containerClassName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"pagination"&lt;/span&gt;
            &lt;span class="na"&gt;activeClassName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"active"&lt;/span&gt;
            &lt;span class="na"&gt;renderOnZeroPageCount&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code provided shows the implementation of a paginated table component. The &lt;code&gt;PaginatedItems&lt;/code&gt; component manages the state for displaying a specific number of items per page and calculating the necessary pagination parameters.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;DropdownFilter&lt;/code&gt; component renders a dropdown menu with options for setting the number of items per page. When an option is clicked, the &lt;code&gt;setItemsPerPage&lt;/code&gt; function is called to update the &lt;code&gt;itemsPerPage&lt;/code&gt; state in the &lt;code&gt;PaginatedItems&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;PaginatedItems&lt;/code&gt; component, the &lt;code&gt;useEffect&lt;/code&gt; hook is used to update the &lt;code&gt;currentItems&lt;/code&gt; state and calculate the &lt;code&gt;pageCount&lt;/code&gt; whenever the &lt;code&gt;users&lt;/code&gt;, &lt;code&gt;itemOffset&lt;/code&gt;, or &lt;code&gt;itemsPerPage&lt;/code&gt; dependencies change. The &lt;code&gt;currentItems&lt;/code&gt; state is updated by slicing the users array based on the current &lt;code&gt;itemOffset&lt;/code&gt; and &lt;code&gt;itemsPerPage&lt;/code&gt; values.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;handlePageClick&lt;/code&gt; function is invoked when the user clicks on a page in the pagination component (&lt;code&gt;ReactPaginate&lt;/code&gt;). It calculates the new &lt;code&gt;itemOffset&lt;/code&gt; based on the selected page and updates the state accordingly.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;PaginatedItems&lt;/code&gt; component also renders the &lt;code&gt;Table&lt;/code&gt; component with the &lt;code&gt;currentItems&lt;/code&gt; as the &lt;code&gt;users&lt;/code&gt; prop, showing the table with the paginated data.&lt;/p&gt;

&lt;p&gt;Additionally, there are UI elements for displaying the current page's range and the total number of users. The &lt;code&gt;ReactPaginate&lt;/code&gt; component handles the pagination rendering and interaction based on the provided parameters.&lt;/p&gt;

&lt;p&gt;After passing the data to the &lt;code&gt;Table&lt;/code&gt; component, I populated the body of the table with the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TableProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// users is a generic of type object just as in he Users component&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;//use index signature for type checking individual objects in the users array.&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Table&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;TableProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;activeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setActiveId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Organization&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Username&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Email&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Phone Number&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Date Joined&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Status&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;orgName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createdAt&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
              &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formattedDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-NG&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;month&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;short&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;minute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;hour12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;

            &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"tr-body"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;orgName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;phoneNumber&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formattedDate&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Inactive&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, the table needs a dropdown for each user, it will be triggered on clicking the ellipsis on the extreme right of the table. The dropdown should look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fetuthz7i73b68un4bgch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fetuthz7i73b68un4bgch.png" alt="Table dropdown" width="597" height="772"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking the view details text should navigate to the user details page. I created a &lt;code&gt;Dropdown.tsx&lt;/code&gt; file in the users folder of the component folder where I implemented the functionality like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DropdownProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;toggleDropdown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;activeId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;setActiveId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Dispatch&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SetStateAction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Dropdown&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toggleDropdown&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;DropdownProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;activeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setActiveId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;toggleDropdown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;
      &lt;span class="na"&gt;onMouseEnter&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setActiveId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onMouseLeave&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setActiveId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;activeId&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;show&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; dropdown`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;
        &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;textDecoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/dashboard/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;viewDetails&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"view icon"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;View Details&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blacklist&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"view icon"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Blacklist User&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;activate&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"view icon"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Activate User&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the component, an unordered list &lt;code&gt;(&amp;lt;ul&amp;gt;)&lt;/code&gt; is rendered. The className of the &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; element is conditionally set based on whether the &lt;code&gt;id&lt;/code&gt; matches the activeId. If they match, the show class ( which makes the dropdown visible ) is added to the element, otherwise it remains empty.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; element has two event handlers: &lt;code&gt;onMouseEnter&lt;/code&gt; and &lt;code&gt;onMouseLeave&lt;/code&gt;. When the mouse enters the element, the &lt;code&gt;setActiveId&lt;/code&gt; function is called with the &lt;code&gt;id&lt;/code&gt; as the argument, setting it as the &lt;code&gt;activeId&lt;/code&gt;. When the mouse leaves the element, the &lt;code&gt;setActiveId&lt;/code&gt; function is called with an empty string, clearing the &lt;code&gt;activeId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; element, there are three list items (&lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;) representing the dropdown options. The first list item contains a Link component that wraps the content. The &lt;code&gt;Link&lt;/code&gt; component is used to create a clickable link that navigates to a specific URL. The to prop of the Link component is set to &lt;code&gt;/dashboard/users/${id}&lt;/code&gt;, which dynamically generates the URL based on the &lt;code&gt;id&lt;/code&gt; prop. This means that clicking on this option will navigate to the user details page for the corresponding &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This component is then imported to the table component and included it in the last element of the table like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Inactive&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
      &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ellipsis&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"ellipsis icon"&lt;/span&gt;
      &lt;span class="na"&gt;onMouseEnter&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setActiveId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dropdown&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;toggleDropdown&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;activeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setActiveId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The end product of the dropdown looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8wbeqcci2eqirlkt2dqy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8wbeqcci2eqirlkt2dqy.gif" alt="gif illustration of dropdown" width="299" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, I rendered the &lt;code&gt;PaginatedItems&lt;/code&gt; component in the users component created in the page folder. Ofcourse, wrapped around the page component initially discussed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PaginatedItems&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/dashboard/users/PaginatedItems&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PaginatedItems&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
     &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have been with me up to this point, congratulations on surviving this wild ride through the &lt;code&gt;User&lt;/code&gt; page. Grab yourself a virtual cookie and take a well-deserved break! But hold on tight because in the next section, we'll be diving into the thrilling world of each user details, where we'll uncover secrets, unravel mysteries, and navigate through the intricacies of individual user profiles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Journey's End: The User Details Page
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsci29thmpltummkzzkw6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsci29thmpltummkzzkw6.png" alt="User Details Page" width="800" height="885"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fortunately, unlike the &lt;code&gt;users&lt;/code&gt; page, the user page only requires implementing the data fetching and UI populating functions. However, there is an interesting twist. Once a user's information has been accessed, it needs to be saved in either the &lt;code&gt;indexedDB&lt;/code&gt; or &lt;code&gt;localStorage&lt;/code&gt;. The purpose of this storage is to avoid unnecessary network queries. If the user details data is already present in the &lt;code&gt;localStorage&lt;/code&gt;, we can simply retrieve it from there instead of making additional network requests.&lt;/p&gt;

&lt;p&gt;To get started, I defined the route to the endpoint that calls a user's details in the &lt;code&gt;requests.ts&lt;/code&gt; file, located in the &lt;code&gt;utils&lt;/code&gt; folder, similar to how I did it for the users endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUserById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This endpoint requires including the &lt;code&gt;id&lt;/code&gt; of each user in its query. Fortunately, with React Router, we can extract this &lt;code&gt;id&lt;/code&gt; from the URL once we have navigated to the user details page. Stay tuned for more exciting details!&lt;/p&gt;

&lt;p&gt;Moving on, I created a file in the &lt;code&gt;pages&lt;/code&gt; folder and named it &lt;code&gt;User-details.tsx&lt;/code&gt; where I imported the previously defined endpoint for it to be called with the &lt;code&gt;id&lt;/code&gt;. This &lt;code&gt;id&lt;/code&gt; will be gotten from the URL with &lt;a href="https://reactrouter.com/en/main/hooks/use-params" rel="noopener noreferrer"&gt;&lt;code&gt;useParams&lt;/code&gt;&lt;/a&gt; provided by react-router and passed to the API route as seen below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/dashboard/common/Page&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useParams&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getUserById&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../utils/requests&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserDetails&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;span class="nx"&gt;JSX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Element&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useParams&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//get id from URL&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="c1"&gt;//markup here&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Following this, I implemented the functionality to fetch and save to &lt;code&gt;localStorage&lt;/code&gt; in the &lt;code&gt;fetchUserDetails&lt;/code&gt; function included in the code snippet below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/dashboard/common/Page&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useParams&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getUserById&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../utils/requests&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserDetails&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;JSX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Element&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useParams&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchUserDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usersFromLocalStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usersFromLocalStorage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;}[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usersFromLocalStorage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;u&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;getUserById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;AxiosResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;getUserById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;AxiosResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
          &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
          &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetchUserDetails&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  // UI population code here
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;UserDetails&lt;/code&gt; component, the &lt;code&gt;fetchUserDetails&lt;/code&gt; function is responsible for fetching and setting the user details. It first checks if the users property exists in the &lt;code&gt;localStorage&lt;/code&gt;. If it does, it searches for a user with a matching id and sets the user state accordingly.&lt;/p&gt;

&lt;p&gt;If no matching user is found, a fresh API call is made using &lt;code&gt;getUserById&lt;/code&gt; and the retrieved data is added to the users array in the &lt;code&gt;localStorage&lt;/code&gt;. The user state is then set with the fetched data.&lt;/p&gt;

&lt;p&gt;In the case where the users property does not exist in the &lt;code&gt;localStorage&lt;/code&gt;, a fresh API call is made to retrieve the user details. The retrieved data is stored in the users array in the &lt;code&gt;localStorage&lt;/code&gt;, and the user state is set with the fetched data.&lt;/p&gt;

&lt;p&gt;After the &lt;code&gt;fetchUserDetails&lt;/code&gt; function is executed, the UI is populated with the relevant user details.&lt;/p&gt;

&lt;p&gt;And thus, our adventurous quest through the intricate realm of user details comes to a triumphant end. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Well, despite my best efforts, one might think they would at least get a chance to proceed to the next stage, right? 😀 However, to my surprise, I received a rejection without the interviewer even signing into the app. Imagine finding out this tidbit from my Firebase Console! Life has a way of throwing unexpected twists in our coding journeys.&lt;/p&gt;

&lt;p&gt;But fear not, my dear readers, for our shared adventure has not been in vain. I extend my deepest appreciation for your unwavering support and for joining me through the lines of code, the challenges, and the triumphs. 👊 Together, we have explored the intricacies of building an admin dashboard, overcoming obstacles along the way.&lt;/p&gt;

&lt;p&gt;If you're curious to see the fruits of our labor, you can find the live site &lt;a href="https://lendsqr-admin-dashboard.netlify.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;, ready to be explored. For those interested in diving into the code, it awaits you on GitHub &lt;a href="https://github.com/SiR-PENt/lendsqr-admin-dashboard" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, as I embark on new opportunities, I want to let you know that I'm still open to exploring frontend developer roles. If you or anyone you know is seeking a dedicated and passionate developer, please reach out to me via email at &lt;a href="mailto:olasunkanmiibalogun@gmail.com"&gt;olasunkanmiibalogun@gmail.com&lt;/a&gt;. I'm eager to learn more about exciting opportunities that lie ahead.&lt;/p&gt;

&lt;p&gt;Thank you once again for being part of this coding journey. Until we meet again in the realm of knowledge and exploration, may your code be bug-free and your programming endeavors be filled with joy and success. Happy coding!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>typescript</category>
      <category>interview</category>
    </item>
    <item>
      <title>How To Use TypeScript Interfaces For Better Code Organization And Readability</title>
      <dc:creator>Olasunkanmi Balogun</dc:creator>
      <pubDate>Sat, 18 Feb 2023 15:10:44 +0000</pubDate>
      <link>https://forem.com/sukodes/how-to-use-typescript-interfaces-for-better-code-organization-and-readability-541a</link>
      <guid>https://forem.com/sukodes/how-to-use-typescript-interfaces-for-better-code-organization-and-readability-541a</guid>
      <description>&lt;p&gt;&lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt; is an add-on for JavaScript. That is, it includes more features and improvements such as syntax for types. TypeScript runs with a compile-time type checker hence you can avoid or debug errors faster when you add types to your code. According to its &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;official website&lt;/a&gt;, it is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale.&lt;/p&gt;

&lt;p&gt;In TypeScript, there are several ways to represent objects, one of those ways includes interfaces. An interface controls the property names an object can have, this means that when an object implements an interface, the object conforms to the rules specified by the interface.&lt;/p&gt;

&lt;p&gt;Interfaces can help achieve code organization and readability which is crucial for maintaining, collaborating, reusing, and optimizing your codebase. In this article, we'll discuss:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Importance Of Interfaces&lt;/li&gt;
&lt;li&gt;
Syntax And Basic Use Cases Of Interfaces

&lt;ul&gt;
&lt;li&gt;Syntax&lt;/li&gt;
&lt;li&gt;Basic Use Cases&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Importance Of Interfaces
&lt;/h2&gt;

&lt;p&gt;Interfaces provide a range of benefits, from improving code consistency and readability to facilitating reuse and catching errors early in the development process. In this section, we'll discuss a few importance of using interfaces in your TypeScript code.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enforce consistency&lt;/strong&gt;: Interfaces let you define a common set of properties and methods that objects must implement, ensuring that the structure and behavior of objects of a given type are the same. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Facilitate documentation&lt;/strong&gt;: Interfaces serve as a place to document the expected properties and methods of an object. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improve Readability&lt;/strong&gt;: By providing the expected structure of an object, including its properties, methods, and types, interfaces make code easier to read especially when working with complex codebases or collaborating with other developers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Catch errors early&lt;/strong&gt;: Enforcing strict type-checking at compile time, interfaces help catch errors before they make it to production. This can save time, effort, and cost.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code Reusability&lt;/strong&gt;: Since interfaces allow you to define custom types that can be used in place of built-in types like &lt;code&gt;number&lt;/code&gt; and &lt;code&gt;string&lt;/code&gt;, it can ensure that code is more reusable thereby reducing duplication and also make the code modular - this means you can export and import it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Syntax And Basic Use Cases Of Interfaces
&lt;/h2&gt;

&lt;p&gt;In this section, we'll get started with interfaces in TypeScript. It's important to understand their syntax and basic use cases - defining and implementing interfaces, and how to use them to enforce type safety in your code. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: To follow along with the code snippets provided, you can use the official &lt;a href="https://www.typescriptlang.org/play" rel="noopener noreferrer"&gt;TypeScript playground&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Syntax
&lt;/h3&gt;

&lt;p&gt;Interfaces are defined using the &lt;code&gt;interface&lt;/code&gt; keyword followed by its name, then the body of the interface in curly braces. Here's an example of an interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We defined an interface and named it &lt;code&gt;User&lt;/code&gt;, it has properties &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt;, both of which are of type &lt;code&gt;string&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;We can now use the &lt;code&gt;User&lt;/code&gt; interface as a natural data type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//define object that conforms to the specification of interface User&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Objects using the &lt;code&gt;User&lt;/code&gt; interface as their type must have the same properties(the keys in the object), as specified in the &lt;code&gt;User&lt;/code&gt; interface. If a property is optional, it can be omitted. If one of the properties is missing or if its value isn't the same data type specified in the interface, then the compiler will throw an error. Hence we cannot add extra fields that are not defined in the interface to the object. &lt;/p&gt;

&lt;p&gt;Let's try to add a new property that was not initially defined in the interface and see what happens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;//new property&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code will cause the TypeScript compiler to throw an error &lt;code&gt;2322&lt;/code&gt;, since the &lt;code&gt;id&lt;/code&gt; property was not initially declared in the interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Type&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{ firstName: string; lastName: string; id: string; }&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;assignable&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt; &lt;span class="nx"&gt;literal&lt;/span&gt; &lt;span class="nx"&gt;may&lt;/span&gt; &lt;span class="nx"&gt;only&lt;/span&gt; &lt;span class="nx"&gt;specify&lt;/span&gt; &lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;does&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;exist&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="mi"&gt;2322&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Basic Use Cases
&lt;/h3&gt;

&lt;p&gt;Now that we already know how interfaces are defined, let's discuss a few use cases.&lt;/p&gt;

&lt;h4&gt;
  
  
  Use Case: Optional Properties
&lt;/h4&gt;

&lt;p&gt;To make a property optional as discussed earlier, you append &lt;code&gt;?&lt;/code&gt; to its name as seen below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//id can now be omitted and the compiler won't throw any errors&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Use Case: Read-only Properties
&lt;/h4&gt;

&lt;p&gt;In cases where we want to make a property &lt;code&gt;read-only&lt;/code&gt; in an interface, we include the &lt;code&gt;readonly&lt;/code&gt; keyword before the name of the property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;dbid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dbid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After &lt;code&gt;dbid&lt;/code&gt;'s first assignment in the &lt;code&gt;user&lt;/code&gt; object, it cannot be reassigned again. Using the &lt;code&gt;readonly&lt;/code&gt; keyword with a property means the property cannot be modified after its first assignment. You can think of its behavior as the same as the &lt;code&gt;const&lt;/code&gt; keyword in JavaScript. Hence, the code below will throw an error &lt;code&gt;2540&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;dbid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dbid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dbid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Error message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Cannot&lt;/span&gt; &lt;span class="nx"&gt;assign&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dbid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;because&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;only&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="mi"&gt;2540&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Use Case: Extending Other Types
&lt;/h4&gt;

&lt;p&gt;When creating new interfaces, we can extend our interfaces so they include properties from other interfaces or types. This way you can extract interfaces that contain the same properties and use them as components for other interfaces.&lt;/p&gt;

&lt;p&gt;From the &lt;code&gt;User&lt;/code&gt; interface in previous examples, let's define a new interface &lt;code&gt;Admin&lt;/code&gt; that also contains the &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt; properties but also contains a new property &lt;code&gt;role&lt;/code&gt;. We can simply extend the &lt;code&gt;Admin&lt;/code&gt; interface from the &lt;code&gt;User&lt;/code&gt; interface. &lt;/p&gt;

&lt;p&gt;See code example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;dbid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Admin&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;developer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dbid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Admin&lt;/code&gt; interface now inherits the properties of the interface &lt;code&gt;User&lt;/code&gt; and also includes its own property &lt;code&gt;role&lt;/code&gt;. It's just as if we did:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Admin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;dbid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="nl"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;developer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extending an interface is not just limited to other interfaces. They can extend from any object type like &lt;a href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-aliases" rel="noopener noreferrer"&gt;normal types&lt;/a&gt;, and also &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-use-classes-in-typescript" rel="noopener noreferrer"&gt;classes&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Use Case: Function Types
&lt;/h4&gt;

&lt;p&gt;We can use interfaces to describe function types. That is, we can define the expected parameter type and expected return type of a function in an interface.&lt;/p&gt;

&lt;p&gt;See code example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AddFunction&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AddFunc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We defined an interface &lt;code&gt;AddFunction&lt;/code&gt; that describes how the parameters and return value of any function that utilizes the interface should look like. You see that after we declared the interface, we didn't need to specify the parameter and return type in the &lt;code&gt;add&lt;/code&gt; function anymore. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The names of the parameters in our function do not need to match the ones defined in our function type.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Use Cases: Index Signatures
&lt;/h4&gt;

&lt;p&gt;Index signatures are a way of defining the shape of an object with dynamic property names or when the properties of an object are not known yet.&lt;/p&gt;

&lt;p&gt;In the code below, we'll see how we can define an index signature for an object whose properties we don't know yet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Score&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;score1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;score2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;score3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, we defined an interface &lt;code&gt;Score&lt;/code&gt; that has an index signature. The &lt;code&gt;key&lt;/code&gt; is a string, and the &lt;code&gt;value&lt;/code&gt; is a number. This simply means that any object(like the &lt;code&gt;score&lt;/code&gt; object above), that utilizes the interface must have its &lt;code&gt;keys&lt;/code&gt; as type string and &lt;code&gt;values&lt;/code&gt; as type number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;While we've discussed some common use cases of interfaces, you should not that there are many more use cases of interfaces in TypeScript. Whether you're working on a large codebase with multiple developers or you just want to improve the quality of your own code, interfaces can be a valuable tool to have in your knowledge base.&lt;/p&gt;

&lt;p&gt;If you're interested in learning more about interfaces in TypeScript, you can explore the documentation and start experimenting with different use cases. &lt;/p&gt;

&lt;p&gt;In conclusion, interfaces are a powerful feature of TypeScript that can provide a range of benefits, from improving code consistency and readability to facilitating reuse and catching errors earlier in the development process. By enforcing consistent types across a codebase, interfaces can help ensure that code is easier to read and understand, more modular and reusable, and less error-prone. &lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to ask them in the comment section.&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>How To Unit Test React Applications with Jest: A Beginner's Guide</title>
      <dc:creator>Olasunkanmi Balogun</dc:creator>
      <pubDate>Thu, 09 Feb 2023 15:34:20 +0000</pubDate>
      <link>https://forem.com/sukodes/how-to-unit-test-react-applications-with-jest-a-beginners-guide-2ppd</link>
      <guid>https://forem.com/sukodes/how-to-unit-test-react-applications-with-jest-a-beginners-guide-2ppd</guid>
      <description>&lt;p&gt;Testing plays a crucial part in ensuring the quality and reliability of your code. With the right knowledge of testing, its methods, and tools, you can ensure your code matches the requirements and is bug-free. &lt;/p&gt;

&lt;p&gt;Testing is a critical aspect of software development, yet it is frequently overlooked and undervalued despite its vital role in ensuring the quality and reliability of applications. Testing is important because it helps identify bugs before a software product is released to its end users.&lt;/p&gt;

&lt;p&gt;In this article, we'll cover what you need to know about unit testing, getting started with unit testing in your React applications using Jest, from setting up Jest in your project to writing tests.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What Is Unit Testing And Why Is It Important?&lt;/li&gt;
&lt;li&gt;Performing Unit Tests With Jest In React&lt;/li&gt;
&lt;li&gt;Mocking Functions With Jest&lt;/li&gt;
&lt;li&gt;Snapshot Testing With Jest&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What Is Unit Testing And Why Is It Important?
&lt;/h2&gt;

&lt;p&gt;Unit testing is an aspect of the overall testing process in software development. It focuses on individual units of an application such as functions, objects, procedures, and so on. The primary purpose of unit tests is to ensure that each unit performs as expected. &lt;/p&gt;

&lt;p&gt;From the definition above, we can deduce that unit testing in React is the testing of individual React components.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Why Is It Important?
&lt;/h3&gt;

&lt;p&gt;Below are some important reasons why we need unit tests.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Unit tests help to set the standard for coding requirements; writing tests while implementing a feature, for example, gives us an idea of how the implementation should be written. &lt;/li&gt;
&lt;li&gt;It prevents developers push bugs to production as it is always mostly detected in the development phase.&lt;/li&gt;
&lt;li&gt;Unit testing simplifies the debugging process.&lt;/li&gt;
&lt;li&gt;Cost-effective - It is cheaper to fix bugs way before a later stage, let's say after it has been pushed to production.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Performing Unit Tests With Jest In React
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Jest is a JavaScript testing framework designed to ensure the correctness of any JavaScript codebase. It allows you to write tests with an approachable, familiar, and feature-rich API that gives you results quickly.   &lt;/p&gt;

&lt;p&gt;-Jest Core Team&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Jest in itself is not a library but a framework, it even has a CLI tool that you can use with the command line. Its &lt;a href="https://jestjs.io/" rel="noopener noreferrer"&gt;official website&lt;/a&gt; emphasizes its focus on simplicity and that's due to its zero config setup. You can start using it as soon as you install it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Create a new React app&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open your terminal and create a new React app using the command below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app unit-testing-tutorial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Install Jest using your favorite package manager&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you use &lt;code&gt;cra(create-react-app)&lt;/code&gt; to create a new React project, it has built-in support for Jest, hence we do not have to install it manually. Hence, the only thing you need to do is install &lt;code&gt;react-test-renderer&lt;/code&gt; for rendering snapshots which will also be covered in this article. You can install it with the command below.&lt;/p&gt;

&lt;p&gt;with &lt;code&gt;npm&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev react-test-renderer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with &lt;code&gt;yarn&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add --dev react-test-renderer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Otherwise, if you are not using &lt;code&gt;cra&lt;/code&gt;, you have to install it manually with your favorite package manager with the command below.&lt;/p&gt;

&lt;p&gt;with &lt;code&gt;npm&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev jest react-test-renderer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with &lt;code&gt;yarn&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add --dev jest react-test-renderer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add the following code to your &lt;code&gt;package.json&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "scripts": {
    "test": "jest"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing A React Component
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;If you used &lt;code&gt;cra&lt;/code&gt; to create your React app, a &lt;code&gt;App.test.js&lt;/code&gt; file would have been created for you by default for testing the &lt;code&gt;App.js&lt;/code&gt; component. To play around, you can run a sample test with the &lt;code&gt;npm run test&lt;/code&gt; command on your terminal to see how testing works.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the following steps, we'll get started with testing our own React component with Jest.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Step 1: Create a Component&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's create a component and call it &lt;code&gt;MyFirstTest&lt;/code&gt;, which simply renders hello with the name passed to its prop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";

function MyFirstTest({ name }) {
    return (
    &amp;lt;h1&amp;gt;Hello {name}!&amp;lt;/h1&amp;gt;
    )
}

export default MyFirstTest;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Step 2: Create A Test File&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, we'll create a test file in the same directory as the component and use the extension &lt;code&gt;.test.js&lt;/code&gt;. The &lt;code&gt;.test.js&lt;/code&gt; extension lets Jest know that this is a test file.&lt;/p&gt;

&lt;p&gt;The test will check if our component is rendered with the correct name passed to it as a prop. The unit test for our component &lt;code&gt;MyFirstTest&lt;/code&gt; can then be written as seen below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { render } from '@testing-library/react';
import MyFirstTest from './MyFirstTest';

test('renders the component with the correct name passed as prop', () =&amp;gt; {

  const { getByText } = render(&amp;lt;MyFirstTest name="Peter"/&amp;gt;);
  const textElement = getByText(/Hello Peter!/i);
  expect(textElement).toBeInTheDocument();

});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can describe the above test as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We define a test case with the test function provided by Jest. The function takes a string that explains what the test is going to do as its first argument and the second argument is a callback function that implements the test logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside the callback function, the first thing we do is render the component we want to test with the render function. The render function returns an object that contains a lot of useful functions that can be used to interact with the rendered component.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From these functions, we utilize the &lt;code&gt;getByText&lt;/code&gt; function. This function searches through the rendered component to find an element that contains the text "Hello Peter".&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: The /i at the end of the string /Hello Peter!/i was used to indicate case insensitivity. Hence, "/i" matches the string "Hello Peter" regardless of the case. i.e HeLLo PETER will still match.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If the component is appropriately rendered, then the element exists in the virtual DOM. We use the &lt;code&gt;expect&lt;/code&gt; function which gives us access to many &lt;a href="https://jestjs.io/docs/using-matchers" rel="noopener noreferrer"&gt;matchers&lt;/a&gt; (like &lt;code&gt;toBeInTheDocument()&lt;/code&gt;) to assert that the element is in the virtual DOM. If it asserts that it's present, the test will pass. Else, the test fails.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run the test with &lt;code&gt;npm run test&lt;/code&gt; command. Your test result should look like the image below.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqja41lpceiszrjqf70vx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqja41lpceiszrjqf70vx.png" alt="Test Result" width="562" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mocking Functions With Jest
&lt;/h2&gt;

&lt;p&gt;When a function is mocked, it means a sample or epitome of that function is created as a replacement for that function for the purpose of testing. Its purpose is to verify its result or behavior in a predictable environment.&lt;/p&gt;

&lt;p&gt;Jest provides several ways we can perform mocking including &lt;code&gt;jest.fn()&lt;/code&gt;, which we can use to ensure predictable results. With &lt;code&gt;jest.fn()&lt;/code&gt; we can create a sample(mock function) that can be used to replace the original function for testing purposes. The mock function can then be configured to return specific values or throw new errors. By mocking functions, we can confirm that components are using functions as expected. Let's look at an example of how to mock a function using &lt;code&gt;jest.fn()&lt;/code&gt; in the following steps.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a file &lt;code&gt;math.js&lt;/code&gt; and copy the following code.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//math.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create another file &lt;code&gt;add.js&lt;/code&gt; and import the &lt;code&gt;add&lt;/code&gt; function from the &lt;code&gt;math.js&lt;/code&gt; file and copy the code below. This way we don't have to worry about the implementation of how the addition is done in the &lt;code&gt;math.js&lt;/code&gt; file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { add } from './math.js';

export const doAdd = (a, b) =&amp;gt; add(a, b);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create a test file &lt;code&gt;add.test.js&lt;/code&gt; and import all exports from the &lt;code&gt;add.js&lt;/code&gt; file as math. This is so they can be accessible in a math object.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as math from './add';

test('adds numbers passed as argument', () =&amp;gt; {
const sum = math.doAdd(1, 2);
expect(sum).toBe(3);
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we assign the &lt;code&gt;math.add&lt;/code&gt; function which adds the two parameters passed to it to the variable &lt;code&gt;sum&lt;/code&gt;. We then use the &lt;code&gt;expect&lt;/code&gt; method which gives us access to the &lt;code&gt;toBe()&lt;/code&gt; matcher to assert that the result of the sum is 3.&lt;/p&gt;

&lt;p&gt;Your test result should look like this after running the test file&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl5yaormr1cf5miwfuar7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl5yaormr1cf5miwfuar7.png" alt="Test Result" width="363" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Snapshot Testing With Jest
&lt;/h2&gt;

&lt;p&gt;Snapshot testing is used when you want to catch unexpected changes in your UI. It is a technique used when the output of a test is being compared against a previously captured snapshot of the expected result to ensure consistency. The test passes if the output of the function matches the previously captured snapshot, if it doesn't, the test fails. In the following steps, we'll see how snapshot tests work by testing a &lt;code&gt;button&lt;/code&gt; component.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a component and name it &lt;code&gt;button.js&lt;/code&gt; and copy the following code
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default function Button() {
    return(
        &amp;lt;button&amp;gt;
            Click Me
        &amp;lt;/button&amp;gt;
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create a test file &lt;code&gt;button.test.js&lt;/code&gt; and copy the following code.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import renderer from 'react-test-renderer';
import Button from './Button';

test('Button should match its snapshot', () =&amp;gt; {
  const button = renderer.create(&amp;lt;Button /&amp;gt;).toJSON();
  expect(button).toMatchSnapshot();
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We import the &lt;code&gt;renderer&lt;/code&gt; method from the &lt;code&gt;react-test-renderer&lt;/code&gt; library that we installed earlier. We then use the &lt;code&gt;renderer.create&lt;/code&gt; method to render the component.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After rendering, the &lt;code&gt;toJSON()&lt;/code&gt; method is called to create a plain JavaScript object that represents the component and its children which is then saved to the variable &lt;code&gt;button&lt;/code&gt;.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We then use the &lt;code&gt;expect&lt;/code&gt; and &lt;code&gt;toMatchSnapshot&lt;/code&gt; functions to compare the button with a saved snapshot.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On testing the file, a &lt;code&gt;__snapshot__&lt;/code&gt; folder is automatically created where snapshots are stored for comparison. You can think of it as where your history of snapshots is stored. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your test result should look like this after you run your test: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhu6kiyw7hvufkdsm8m4l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhu6kiyw7hvufkdsm8m4l.png" alt="Test Result" width="464" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If there are any changes later(after the first snapshot was taken), Jest will throw an error and ask if you want to update the snapshot.&lt;/p&gt;

&lt;p&gt;As a codebase evolves, Snapshot tests are often used in conjunction with unit tests to ensure that the output of a function remains consistent over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In conclusion, we see that unit testing is a critical aspect of software development that helps to ensure the quality and reliability of our code. It is an efficient way to validate that individual units of code work as intended, reducing the chances of us pushing bugs to production. So far, we have learned about Jest, how we can mock a function with Jest, and how to test using snapshots. Jest has a lot of other features that were not mentioned here, be sure to get your hands dirty. With the right understanding and use of these tools, we can make our testing process more effective and save time.&lt;/p&gt;

</description>
      <category>crypto</category>
      <category>cryptocurrency</category>
      <category>blockchain</category>
      <category>web3</category>
    </item>
    <item>
      <title>Maximizing Performance: A deep dive into React re-renders and how to optimize your components</title>
      <dc:creator>Olasunkanmi Balogun</dc:creator>
      <pubDate>Fri, 27 Jan 2023 14:57:04 +0000</pubDate>
      <link>https://forem.com/sukodes/maximizing-performance-a-deep-dive-into-react-re-renders-and-how-to-optimize-your-components-12ic</link>
      <guid>https://forem.com/sukodes/maximizing-performance-a-deep-dive-into-react-re-renders-and-how-to-optimize-your-components-12ic</guid>
      <description>&lt;p&gt;React is a powerful tool for building complex user interfaces, but as the size of your application grows, so do the performance issues. One of the most common performance issues developers encounter is unnecessary re-renders caused by a component's state or props changing too many times. In this article, we will take a deep dive into React re-renders, and explore techniques for maximizing the performance of your components. From understanding when and why a component re-renders, to implementing best practices such as React.memo, this article will provide you with the knowledge you need to optimize the performance of your React applications, we'll explore the intricacies of React re-renders and reveal how to make your components perform at their best. Let's embark on this adventure together and uncover the secrets of creating high-performing React applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Importance Of Performance In React.&lt;/li&gt;
&lt;li&gt;Understanding React Re-renders.&lt;/li&gt;
&lt;li&gt;Common Antipatterns And Best Practices To Improve Performance.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Importance Of Performance In React
&lt;/h2&gt;

&lt;p&gt;React is one of the most popular front-end libraries, and as it's widely used in building dynamic and interactive web applications, it's crucial to ensure that the performance of React applications is optimized to provide a smooth and responsive user experience. Performance is an important part of any application and poor performance can lead to slow page load times, laggy user interactions, slow development time, insecurity, and a poor overall user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding React Re-renders
&lt;/h2&gt;

&lt;p&gt;When thinking about a React application's performance, there are two stages we should really be concerned about, they are:&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;initial render&lt;/strong&gt; stage which generally happens when the component appears on the screen.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;re-render&lt;/strong&gt; stage which is the second or subsequent render that happens after the component is already on the screen. Re-renders happen when there's an update in a React's components state. An update can occur as a result of a user's interaction with the site or a component making asynchronous requests.&lt;/p&gt;

&lt;p&gt;Re-renders can take a toll on an application's performance if there are too many unnecessary re-renders. Sparingly, unnecessary re-renders are not a problem since React engines are very fast and can deal with re-renders without being noticeable. However, an application more than adequately re-rendering could result in performance issues such as laggy user interactions as aforementioned, or even break the app completely. Let's take a look at some reasons that could cause re-renders in React. A component re-renders when:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When State Updates&lt;/li&gt;
&lt;li&gt;When Parent Component re-renders&lt;/li&gt;
&lt;li&gt;
When Props Update &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  When State Updates
&lt;/h3&gt;

&lt;p&gt;When the state of a component is updated, the component re-renders itself to reflect the update made to the state. Let's take a look at the code illustration below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/re-render-due-to-state-update-u16y31" rel="noopener noreferrer"&gt;See practical example on CodeSandbox.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above example, when the button is clicked, state is updated. Hence, causing the whole component to re-render. &lt;/p&gt;

&lt;h3&gt;
  
  
  When Parent Component Re-renders
&lt;/h3&gt;

&lt;p&gt;Naturally, when the parent of a component re-renders i.e when its state is updated, it causes a not memoized child component to also re-render whether its props have changed or not. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/re-render-due-to-parents-update-2ctnc3?file=/src/App.js" rel="noopener noreferrer"&gt;See practical example on CodeSandbox.&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;We saw on the console that the child component also re-renders even when the prop, &lt;code&gt;name&lt;/code&gt;, doesn't change. &lt;/p&gt;

&lt;h3&gt;
  
  
  When Props Update
&lt;/h3&gt;

&lt;p&gt;Re-render due to props update only matters when memoization methods such as &lt;code&gt;React.memo&lt;/code&gt; are used. That way, child component re-renders are restricted to only when its prop values update. &lt;/p&gt;

&lt;h2&gt;
  
  
  Common Antipatterns And Best Practices To Improve Performance
&lt;/h2&gt;

&lt;p&gt;We will now explore the common antipatterns that developers make when working with React that can lead to unnecessary re-renders in a React application, we will also look at best practices for optimizing the performance of React components, and tips for identifying and preventing unnecessary re-renders. Let's dive in...&lt;/p&gt;

&lt;h3&gt;
  
  
  Preventing Re-renders With Compartmentalization
&lt;/h3&gt;

&lt;p&gt;Compartmentalization is the practice of breaking down a complex component into smaller, more manageable components. &lt;/p&gt;

&lt;p&gt;Apart from the fact that this helps to improve the code's maintainability and reusability and makes it easier to think about the component's behavior, this can also help us prevent unnecessary re-renders. Let's see how...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/preventing-re-renders-by-compartmentalization-pcfb32?file=/src/App.js" rel="noopener noreferrer"&gt;See how compartmentalization can help prevent unnecessary re-renders on CodeSandbox&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;We see how by compartmentalization, the compartmentalized component prevents the re-rendering of the whole component, thereby preventing random component from re-rendering every time the button is clicked. &lt;/p&gt;

&lt;h3&gt;
  
  
  Nested Components
&lt;/h3&gt;

&lt;p&gt;It is generally bad practice to nest components. Nesting components in another component can make your app really slow. &lt;/p&gt;

&lt;p&gt;Assuming there is an update in the state of the parent component causing it to re-render, the nested component doesn't just re-render with the parent but also re-mounts i.e React destroys the component and then re-create it all over again from scratch. This is a process that is going to be slower than a normal re-render given the circumstances. Assuming the nested component makes a request to an API with &lt;code&gt;useEffect&lt;/code&gt; without any dependency, then the function will be triggered every time the parent re-renders. This can cause bugs you don't want. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/nested-component-illustration-seje6v?file=/src/App.js" rel="noopener noreferrer"&gt;See a practical on CodeSandbox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to prevent this, child components should be written separately to avoid being left in a performance hole.&lt;/p&gt;

&lt;h3&gt;
  
  
  Passing Children As Props
&lt;/h3&gt;

&lt;p&gt;Passing children as props is somewhat like the concept of compartmentalization afore explained. The difference is that the component that updates the state is extracted and is used to wrap the child component which is passed to it as &lt;code&gt;children&lt;/code&gt;. That way, the parent component sees the children as props, therefore child components won't be re-rendered.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/passing-children-as-props-v9hn9b?file=/src/App.js" rel="noopener noreferrer"&gt;See practical example on CodeSandbox&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preventing Re-renders With &lt;code&gt;React.memo&lt;/code&gt; And &lt;code&gt;useMemo&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;As your React application grows in complexity, it is important to optimize components to prevent performance issues.&lt;code&gt;React.memo&lt;/code&gt; helps us to ensure that a component re-renders only when necessary. &lt;code&gt;React.memo&lt;/code&gt; is a higher-order component that allows us to wrap functional components and only re-render them when their props have changed. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/preventing-re-render-with-react-memo-ydt9kp?file=/src/App.js" rel="noopener noreferrer"&gt;See practical example on CodeSandbox.&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, note that interestingly, if the child component has a prop that is not a primitive type (i.e if they are not strings, numbers, or boolean) then memoizing your component with &lt;code&gt;React.memo&lt;/code&gt; alone won't be enough to prevent your component from re-rendering even though its prop has not changed unfortunately. Check out Alex Sidorenko's &lt;a href="https://alexsidorenko.com/blog/react-render-props/" rel="noopener noreferrer"&gt;article&lt;/a&gt; to read more as to why this is. Fortunately, there is a way we can work around this and that's where &lt;code&gt;useMemo&lt;/code&gt; comes in handy. With &lt;code&gt;useMemo&lt;/code&gt; hook you can memoize the non-primitive prop to prevent the component from re-rendering unless the prop updates. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/prevent-re-rendering-with-react-memo-and-usememo-fcc1fp" rel="noopener noreferrer"&gt;See practical example on CodeSandbox.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Improving Performance Of Lists
&lt;/h3&gt;

&lt;p&gt;One of the most important aspects of working with lists in React is using keys. Keys are unique identifiers that help React keep track of which items in a list have been added, removed, or moved. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The algorithm for the re-render phase of lists using keys in React involves generating "before" and "after" snapshots of the elements, identifying existing elements to be re-used, using the "key" attribute to match items with the same "before" and "after" key and defaulting to using sibling indexes as the key if none is provided, unmounting items that no longer exist, creating new items, and updating existing items.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Without keys or appropriate use of keys, React will have a hard time determining which elements have changed, resulting in unnecessary re-renders, unnecessary re-mounts, and poor performance. However, we should not just provide keys just for the sake of providing keys to the list, it doesn't guarantee the improvement of performance in lists. &lt;/p&gt;

&lt;p&gt;We will now discuss what's considered best practice and what's considered an antipattern.&lt;/p&gt;

&lt;h4&gt;
  
  
  Index As Key
&lt;/h4&gt;

&lt;p&gt;It is okay to use the index of the array as key, however, this depends on if the array is constantly being modified or not i.e they are static. Generally, It is considered best practice to provide strings that are consistent between re-renders as keys. Learn more about this &lt;a href="https://www.developerway.com/posts/react-key-attribute" rel="noopener noreferrer"&gt;here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/illustrating-list-performance-with-static-lists-q43wij?file=/src/App.js" rel="noopener noreferrer"&gt;See practical example for static list on CodeSandbox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/illustration-for-dynamic-lists-3utrln" rel="noopener noreferrer"&gt;See practical example for dynamic list on CodeSandbox&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Random values as key
&lt;/h4&gt;

&lt;p&gt;Providing random values as key is a very big performance killer given how the algorithm to re-render lists in React works. Rather than the items just re-rendering on every state update, React re-mounts the items all over again. This can really slow down our app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/random-keys-antipattern-08r51b?file=/src/App.js" rel="noopener noreferrer"&gt;See practical example on CodeSandbox&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, maximizing performance in React is crucial for creating smooth and responsive user experiences. By understanding the re-render process and using techniques such as &lt;code&gt;React.memo&lt;/code&gt; and &lt;code&gt;useMemo&lt;/code&gt;, as well as implementing strategies like using keys appropriately to avoid unnecessary re-renders, you can ensure that your React applications run at optimal speed. Remember to also keep an eye out for common antipatterns and to constantly monitor and test your application's performance. With the knowledge and techniques discussed in this article, you can take your React development skills to the next level and create high-performing, efficient applications.&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>cloud</category>
      <category>webdev</category>
      <category>gratitude</category>
    </item>
    <item>
      <title>Closures in JavaScript</title>
      <dc:creator>Olasunkanmi Balogun</dc:creator>
      <pubDate>Sun, 13 Feb 2022 12:47:13 +0000</pubDate>
      <link>https://forem.com/sukodes/closures-in-javascript-4o85</link>
      <guid>https://forem.com/sukodes/closures-in-javascript-4o85</guid>
      <description>&lt;p&gt;In my last &lt;a href="https://dev.to/sukodes/understanding-scope-in-javascript-1h66"&gt;post&lt;/a&gt;, we talked about scope in JavaScript and how functions can be inside of functions. In this article, we will talk about closures and how it is related to scope.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I have come to realize that some of us JavaScript devs use closures without even realizing it, funny eh?.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;How closures work in JavaScript can be quite difficult to grasp, but I will try my best to take it step by step in this article. But first, let's know what closures are.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a closure?
&lt;/h2&gt;

&lt;p&gt;A closure allows access(of variables) from an inner function to a parent function. Consider the code below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzsd955h87s7lg5p8na87.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzsd955h87s7lg5p8na87.jpeg" alt="Closure explanation" width="506" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We see in the above code, how that &lt;code&gt;function innerFunc&lt;/code&gt; has access to the &lt;code&gt;variable a&lt;/code&gt; which was declared in the outer &lt;code&gt;function func&lt;/code&gt;. We can therefore call &lt;code&gt;function innerFunc&lt;/code&gt; a closure.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that outer functions cannot have access to variables in their inner functions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;In line 9 of the code above, we called the &lt;code&gt;function func&lt;/code&gt; and assigned it to a variable inner which makes it a function we can later call in the next line. This was done like this because calling the function directly without assigning it to a variable will only just return the &lt;code&gt;innerFunc function&lt;/code&gt; which is not reusable.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In line 10, we see how that &lt;code&gt;function inner&lt;/code&gt; returns 7.&lt;/p&gt;

&lt;p&gt;Now that we have seen a practical example of a closure. Let's get into how closures work in JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do closures work?
&lt;/h2&gt;

&lt;p&gt;Well, for us to really understand how closures work in JavaScript, we have to first understand some of the basics of how JavaScript works(more on that in a future article). There are two important concept in JavaScript that we have to know. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Execution Context &lt;/li&gt;
&lt;li&gt;The Lexical Environment&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. The Execution Context
&lt;/h2&gt;

&lt;p&gt;An execution context refers to an environment where JavaScript code is executed. Talk about functions, variables in functions etc. Two codes can be run in the execution context.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The global code: When a global code is executed, it is executed in global context.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The function code: When a function code is executed, it is executed in the function context.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A collection of active execution context forms an execution stack or a call stack.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For example, we'll assume an execution stack as an array before we continue.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;EStack = [];&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;The stack is pushed every time we call a new function&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When you are running a global code, the stack array contains the global code which looks like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;EStack = [ globalContext ];&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When it encounters a function call, the function goes to the top of the stack, the stack then looks like this.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;EStack = [&lt;br&gt;
functionContext&lt;br&gt;
globalContext&lt;br&gt;
]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After the function code completes, it gets popped off from the stack. The stack then looks like this.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;EStack = [&lt;br&gt;
 globalContext&lt;br&gt;
]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;The global context is usually at the bottom of the stack.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lexical Environment
&lt;/h2&gt;

&lt;p&gt;As the execution context executes the global and function code, it creates a lexical environment where it stores all the variables defined in that function.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;environment record&lt;/strong&gt;(inner environment) and the &lt;strong&gt;reference to the outer environment record&lt;/strong&gt; are all contained in the lexical environment.&lt;/p&gt;

&lt;p&gt;Let's see how the concept of a lexical environment looks like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lexicalEnvironment = {
  environmentRecord: {
    &amp;lt;identifier&amp;gt; : &amp;lt;value&amp;gt;, //inner environment record
    &amp;lt;identifier&amp;gt; : &amp;lt;value&amp;gt;  //inner environment record 
  }
  outer: &amp;lt; Reference to the parent environment &amp;gt; //outer environment record 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's understand the illustration above with a code snippet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let a = 3;

function func() {
  let b = 4;  
}
func();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the code above is run, a global execution context is created for the global code and a function execution context is created for the function code where a lexical environment that stores variables and functions is also created. &lt;/p&gt;

&lt;p&gt;Let's tackle what's happening in the global execution context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;globalLexicalEnvironment = {
  environmentRecord: {
      a    : 3,
      func : &amp;lt; reference to function object &amp;gt;
  }
  outer: null
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We see from the above illustration that the outer environment record is set to null. This is because a global code is the outermost scope of a program. Therefore it has no outer lexical environment.&lt;/p&gt;

&lt;p&gt;Like for the global code above, an execution context is also created for the function code. Only that this is a function execution context. The function lexical environment will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;functionLexicalEnvironment = {
  environmentRecord: {
      b    : 4,
  }
  outer: &amp;lt;globalLexicalEnvironment&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We see that the outer environment is set to the global lexical environment because the function is wrapped inside the global scope. &lt;/p&gt;

&lt;p&gt;Remember, when we were explaining the environment context above we said that after a function code has been run, its function execution context gets popped off from stack. The case isn't the same for its lexical environment though, as it may or may not get popped off on condition of whether it is being referenced by an inner environment or not. Understanding this plays a big role in how closures work.&lt;/p&gt;

&lt;p&gt;Below, we are going to see such condition where it doesn't get popped off.&lt;/p&gt;

&lt;p&gt;Consider the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function firstFunc() {
  let a = 3;

  return function secondFunc() {
    let b = 4;
    return a + b;
  };
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code snippet above, the execution context of the function &lt;code&gt;firstFunc&lt;/code&gt; will be popped off from the stack but its lexical environment won't because it's variable &lt;code&gt;a&lt;/code&gt; is being referenced by it's inner function &lt;code&gt;secondFunc&lt;/code&gt;. Thus, the lexical environment of the &lt;code&gt;firstFunc&lt;/code&gt; and &lt;code&gt;secondFunc&lt;/code&gt; will look like this respectively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firstFuncLexicalEnvironment = {
  environmentRecord: {
    a:  3,
    SecondFunc : &amp;lt; reference to function object &amp;gt;
  }
  outer: &amp;lt;globalLexicalEnvironment&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;secondFuncLexicalEnvironment = {
  environmentRecord: {
    b : 4,
  }
  outer: &amp;lt;firstFuncLexicalEnvironment&amp;gt;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We see in the &lt;code&gt;secondFunc&lt;/code&gt; lexical environment that the outer environment it references is the &lt;code&gt;firstFunc&lt;/code&gt; function. This is because &lt;code&gt;secondFunc&lt;/code&gt; references a variable &lt;code&gt;a&lt;/code&gt; which is not defined in its scope. Noticing that &lt;code&gt;secondFunc&lt;/code&gt; references a variable that is not defined in it's scope, the JavaScript engine looks into the outer environment which is &lt;code&gt;firstFunc&lt;/code&gt; in this case, and then finds the variable &lt;code&gt;a&lt;/code&gt;. Then 7&lt;code&gt;(a + b)&lt;/code&gt; is returned. &lt;/p&gt;

&lt;p&gt;If the lexical environment of the &lt;code&gt;firstFunc&lt;/code&gt; is also popped off as it's execution context, we will get an error that says &lt;code&gt;a is not defined&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now that we have come to the end of the article, let's review what we learnt so far.&lt;/p&gt;

&lt;p&gt;We learnt about &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Closures, &lt;/li&gt;
&lt;li&gt;How closures work,&lt;/li&gt;
&lt;li&gt;The Execution Context and the lexical Environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope that from this article, you have been able to get an understanding of how closures work in JavaScript.&lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to ask them in the comment section. Until next time, XOXO.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Understanding scope in JavaScript</title>
      <dc:creator>Olasunkanmi Balogun</dc:creator>
      <pubDate>Mon, 31 Jan 2022 03:11:56 +0000</pubDate>
      <link>https://forem.com/sukodes/understanding-scope-in-javascript-1h66</link>
      <guid>https://forem.com/sukodes/understanding-scope-in-javascript-1h66</guid>
      <description>&lt;p&gt;In this article, we are going to talk about an important concept of JavaScript called &lt;code&gt;scope&lt;/code&gt;. You will learn about how scope in JavaScript works, and global variables and how they relate to scope.&lt;/p&gt;

&lt;p&gt;Let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is scope in JavaScript?
&lt;/h2&gt;

&lt;p&gt;Scope simply means variable access, that is "What variable do I have access to when my code runs?". By default in JavaScript,&lt;br&gt;
we are in the root scope, alias the window object. Let's visualize what we are talking about here.&lt;/p&gt;

&lt;p&gt;Assume we write and run a function in your browser console, call it &lt;code&gt;func&lt;/code&gt; as shown below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; function func() {
  console.log('func');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...and then call the window object, by just typing &lt;code&gt;window&lt;/code&gt; on the console, you see that your function func has been added to the window object. As shown in the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F37qyj7j3lq943kby0n1y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F37qyj7j3lq943kby0n1y.png" alt="Window Object" width="387" height="405"&gt;&lt;/a&gt;&lt;br&gt;
So, we see now that while working in the browser, the window is the root scope, the parent scope. &lt;/p&gt;

&lt;p&gt;Now, what if we define a function func, then define a variable &lt;code&gt;a&lt;/code&gt; inside it and try to &lt;code&gt;console.log(a)&lt;/code&gt; outside the function, what do we get? Well, let's see for ourselves...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcert6194nq9bcg1zj0wi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcert6194nq9bcg1zj0wi.png" alt="scope of variable a" width="380" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hmnnnn... so we got an error which says a is not defined, let's get a hang of what's happening here. Variable a is defined, but within the function func, right. Variable 'a' therefore is limited to that function's scope(within the curly braces of the function). That is, it cannot be used outside of that scope. The only way to correct the given error is to console.log(a) inside the function's scope. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyaqp2ynaaze1gdqyf5yw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyaqp2ynaaze1gdqyf5yw.png" alt="a is logged on the console" width="380" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We see from the illustration above that a is now logged on the console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Global variables and Scope
&lt;/h2&gt;

&lt;p&gt;Global variables are variables that are declared in the global scope. That is, they are declared in the root scope, which means they are present in the window object like we saw previously. &lt;/p&gt;

&lt;h3&gt;
  
  
  What does this mean?
&lt;/h3&gt;

&lt;p&gt;This means that they can be accessed from anywhere in the JavaScript program, even if they were not declared in the scope of an entirely new function(a child scope). &lt;/p&gt;

&lt;p&gt;Suppose we have a &lt;code&gt;variable a&lt;/code&gt; declared outside of a &lt;code&gt;function func&lt;/code&gt;, the &lt;code&gt;variable a&lt;/code&gt; can be used as a variable, and even modified in a child scope &lt;code&gt;function func&lt;/code&gt;. &lt;br&gt;
Let's visualize what we have just learned. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4zjcsimdbgof5fa78ofb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4zjcsimdbgof5fa78ofb.png" alt="Accessing global variables" width="517" height="224"&gt;&lt;/a&gt;&lt;br&gt;
We see how that the global variable can be accessed and used by child scopes in the above illustration. &lt;/p&gt;

&lt;p&gt;Next, let's see how the global variable can be modified by child scopes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faf28pu67xop7wx158ir3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faf28pu67xop7wx158ir3.png" alt="Modifying global variables" width="521" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We see how that &lt;code&gt;variable a&lt;/code&gt; has been modified globally, not just in the function, after the function was called, and from that instant, a is equal to 13.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We do have many more scenarios of using parent scopes inside of child scopes, like functions inside of functions, but that is beyond the scope of this article. &lt;/p&gt;

&lt;h3&gt;
  
  
  Recap
&lt;/h3&gt;

&lt;p&gt;In this article, you read about&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Root scope and how that by default we are in the root scope, the window object in JavaScript.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How that declaring variables inside of a function is limited to that function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Global variables and how you can use them in child scopes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you have any questions, feel free to ask in the comments section. Until next time, XOXO.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
