DEV Community: Adebayo Olamilekan The latest articles on DEV Community by Adebayo Olamilekan (@oleanji). https://dev.to/oleanji 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%2F905953%2F7605a9ae-5a5f-428b-a32b-97c6ab38aacb.jpg DEV Community: Adebayo Olamilekan https://dev.to/oleanji en Building And Deploying A Subgraph (Part 2) Adebayo Olamilekan Sun, 03 Mar 2024 20:37:04 +0000 https://dev.to/oleanji/building-and-deploying-a-subgraph-part-2-4798 https://dev.to/oleanji/building-and-deploying-a-subgraph-part-2-4798 <p>Just like how fries can be eaten alone 🍟 or eaten together with either ketchup or mayonnaise, this tutorial is both <strong>1)</strong> a standalone tutorial for deploying and querying a subgraph. <strong>2)</strong> a continuation from my <a href="proxy.php?url=https://dev.to/oleanji/build-your-personal-crypto-savings-dapp-part-1-contract-5g8b">previous tutorial</a> on building a savings dapp.</p> <h2> <strong>Table of contents</strong> </h2> <ol> <li>Prerequisites</li> <li>Introduction</li> <li>Tips to know about subgraphs</li> <li>Initialize Subgraph</li> <li>Tweak Code and Deploy</li> <li>Querying Subgraph</li> <li>Conclusion</li> </ol> <h3> <strong>Prerequisites</strong> <a></a> </h3> <p>To build, deploy, and query from a subgraph you will need the following essentials:</p> <ul> <li>A deployed smart contract (whether verified or not),</li> <li>a crypto wallet,</li> <li>a <a href="proxy.php?url=https://thegraph.com/studio/" rel="noopener noreferrer">subgraph studio</a> account,</li> <li>and a cup of coffee β˜•.</li> </ul> <p>Before we start building the subgraph project, ensure you have the following above, done? now take a sip 🍡 and let's start building.</p> <h3> <strong>Introduction</strong> <a></a> </h3> <p>A <strong>subgraph</strong> according to <a href="proxy.php?url=https://thegraph.com/" rel="noopener noreferrer">The Graph</a> (which is a decentralized protocol for indexing and querying blockchain data) is a custom API built on blockchain data. They are queried using the GraphQL query language and are deployed to a Graph Node using the Graph CLI.</p> <p>In simpler terms, a subgraph is like a customizable API for easily querying and getting specific data from a blockchain using GraphQL.</p> <p>To get started, we need to have a <a href="proxy.php?url=https://thegraph.com/studio/" rel="noopener noreferrer">subgraph studio</a> account, which is very easy to do in 2 simple steps;</p> <ul> <li>Connect your wallet and </li> <li>Sign a message, then you should have a page like this;</li> </ul> <p><a href="proxy.php?url=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%2Fe55xr7fdqrhs54kbyhaq.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fe55xr7fdqrhs54kbyhaq.png" alt="studio" width="800" height="379"></a></p> <p>Click on the <strong><em>Create a Subgraph</em></strong> button and enter a subgraph name. You have successfully created a subgraph. well-done!!</p> <h2> <strong>Tips to know about subgraphs</strong> <a></a> </h2> <ol> <li>Deleting a subgraph is not possible once it's created.</li> <li>Once a subgraph is created, the name cannot be changed.</li> <li>To enable faster and more easy querying of data from a subgraph, the contract associated with it should emit events.</li> <li>Subgraph mappings are written in AssemblyScript therefore using libraries like <a href="proxy.php?url=https://docs.ethers.org/v5/" rel="noopener noreferrer">ether.js</a> in the subgraph is not possible.</li> </ol> <p>You can check out more of the tips or FAQs of a subgraph <a href="proxy.php?url=https://thegraph.com/docs/en/developing/developer-faqs/" rel="noopener noreferrer">here</a></p> <h2> <strong>Initialize Subgraph</strong> <a></a> </h2> <p>On the lower right side (you will have to scroll down) of your <a href="proxy.php?url=https://thegraph.com/studio/" rel="noopener noreferrer">dashboard</a> page of the subgraph you just created, steps on how to <strong>Initialize</strong>, <strong>Deploy</strong> and <strong>Build</strong> the subgraph are shown.</p> <p><a href="proxy.php?url=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%2Fo20cpduhnuuvlw7jrodk.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fo20cpduhnuuvlw7jrodk.png" alt="Iion" width="800" height="310"></a></p> <h3> Following the steps; </h3> <ul> <li>We need to install the graph cli before a subgraph can be initialized. </li> </ul> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>npm install -g @graphprotocol/graph-cli or yarn global add @graphprotocol/graph-cli </code></pre> </div> <ul> <li>After the installation, run the below </li> </ul> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>graph init --studio &lt;SUBGRAPH_NAME&gt; </code></pre> </div> <p>Here you will be asked for the <em>protocol</em>, <em>chain</em> and other information of the contract you want to subgraph, following the <a href="proxy.php?url=https://dev.to/oleanji/build-your-personal-crypto-savings-dapp-part-1-contract-5g8b">last tutorial</a> of writing, deploying and verifying our crypto-saves smart contract, these are the answers to the questions from the terminal:</p> <ul> <li>Protocol: <code>ethereum</code> </li> <li>Subgraph Slug: <code>Crypto-Saves</code> (or any name you want)</li> <li>Directory to create the subgraph in: <code>Crypto-Saves</code> (or anywhere you want)</li> <li>Ethereum Network: <code>mumbai</code> (the chain where the contract was deployed)</li> <li>Contract Address: <code>0x4b1d98af1af713456c1fc86afed67b94c4648f6d</code> (Contract Address)</li> </ul> <p><a href="proxy.php?url=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%2Fsio9k7hicilxhzpchdn5.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fsio9k7hicilxhzpchdn5.png" alt="Iption" width="492" height="84"></a></p> <p><a href="proxy.php?url=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%2Fsaslccwov887dk8zso9r.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fsaslccwov887dk8zso9r.png" alt="instal" width="504" height="334"></a></p> <ul> <li>After you receive the <strong>Subgraph created</strong> message then run the next command; </li> </ul> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>graph auth --studio &lt;DEPLOY_KEY&gt; cd &lt;Name_of_subgraph&gt; </code></pre> </div> <ul> <li>Using the events of the contract, the graph auto-generates the subgraph's code which needs little to no tweaking before deployment and publishing. The command below auto-generates the code and then builds it. </li> </ul> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>graph codegen &amp;&amp; graph build </code></pre> </div> <p><a href="proxy.php?url=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%2F013fifvqrp0cft4asn98.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F013fifvqrp0cft4asn98.png" alt="n" width="800" height="392"></a></p> <p>Now take another sip of that coffee β˜•</p> <h2> <strong>Tweak Code and Deploy</strong> <a></a> </h2> <p>Navigate to the <code>src</code> folder in the subgraph root directory, then check the auto-generated file, <a href="proxy.php?url=https://thegraph.com/" rel="noopener noreferrer">the graph</a> does splendid work and most times the file doesn't need tweaking and you can just deploy directly, but following my tutorial (<strong>Personal Crypto Savings Dapp</strong>) series, a little tweaking is needed.</p> <p>Change the code in the <code>schema.graphql</code> file in the root directory to the following updated code:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>type EtherLocked @entity(immutable: true) { id: ID! name: String! # string owner: Bytes! # address amount: BigInt! # uint256 releaseTime: BigInt! # uint256 lockType: String! locked: Boolean blockNumber: BigInt! blockTimestamp: BigInt! transactionHash: Bytes! } type EtherUnlocked @entity(immutable: true) { id: ID! name: String! # string owner: Bytes! # address amount: BigInt! # uint256 locked: Boolean blockNumber: BigInt! blockTimestamp: BigInt! transactionHash: Bytes! } type LockupTimeExtended @entity(immutable: true) { id: ID! name: String! # string owner: Bytes! # address releaseTime: BigInt! # uint256 blockNumber: BigInt! blockTimestamp: BigInt! transactionHash: Bytes! } type OwnershipTransferred @entity(immutable: true) { id: ID! previousOwner: Bytes! # address newOwner: Bytes! # address blockNumber: BigInt! blockTimestamp: BigInt! transactionHash: Bytes! } </code></pre> </div> <p>Here I updated the schema and changed some types for better querying results. After this run:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>graph codegen </code></pre> </div> <p>This would update the <code>generated</code> folder with the new types and fields obtained from the update of the <code>schema.graphql</code>, to complete this we will need to change some things in a file under the <code>src</code> folder to:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>import { EtherLocked as EtherLockedEvent, EtherUnlocked as EtherUnlockedEvent, LockupTimeExtended as LockupTimeExtendedEvent, OwnershipTransferred as OwnershipTransferredEvent, } from "../generated/CryptoSaves/CryptoSaves"; import { EtherLocked, EtherUnlocked, LockupTimeExtended, OwnershipTransferred, } from "../generated/schema"; export function handleEtherLocked(event: EtherLockedEvent): void { let entity = EtherLocked.load(event.params.id.toString()); if (!entity) { entity = new EtherLocked(event.params.id.toString()); } entity.name = event.params.name; entity.owner = event.params.owner; entity.amount = event.params.amount; entity.releaseTime = event.params.releaseTime; entity.lockType = event.params.lockType; entity.locked = true; entity.blockNumber = event.block.number; entity.blockTimestamp = event.block.timestamp; entity.transactionHash = event.transaction.hash; entity.save(); } export function handleEtherUnlocked(event: EtherUnlockedEvent): void { let entity = EtherLocked.load(event.params.id.toString()); if (!entity) { return; } entity.locked = false; entity.blockNumber = event.block.number; entity.blockTimestamp = event.block.timestamp; entity.transactionHash = event.transaction.hash; entity.save(); } export function handleLockupTimeExtended(event: LockupTimeExtendedEvent): void { let entity = EtherLocked.load(event.params.id.toString()); if (!entity) { return; } entity.releaseTime = event.params.releaseTime; entity.blockNumber = event.block.number; entity.blockTimestamp = event.block.timestamp; entity.transactionHash = event.transaction.hash; entity.save(); } export function handleOwnershipTransferred( event: OwnershipTransferredEvent ): void { let entity = new OwnershipTransferred(event.transaction.hash.toString()); entity.previousOwner = event.params.previousOwner; entity.newOwner = event.params.newOwner; entity.blockNumber = event.block.number; entity.blockTimestamp = event.block.timestamp; entity.transactionHash = event.transaction.hash; entity.save(); } </code></pre> </div> <p>I am essentially doing another layer of checks before updating the fields after each event has been emitted.</p> <h3> Deploy </h3> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>graph deploy --studio &lt;SUBGRAPH_NAME&gt; </code></pre> </div> <p>This deploys your subgraph to production, enabling querying from either the playground or in your front-end application.</p> <p><a href="proxy.php?url=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%2F7x87ctsazl3dimjievp1.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F7x87ctsazl3dimjievp1.png" alt="on" width="800" height="151"></a></p> <h2> Querying Subgraph <a></a> </h2> <p>A subgraph can be queried from the frontend application or from the playground that the <strong>subgraph studio</strong> offers, which I find very helpful. </p> <p><a href="proxy.php?url=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%2F1qwynjt2e9k33phm0zwj.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F1qwynjt2e9k33phm0zwj.png" alt="Imdescription" width="800" height="357"></a></p> <p>Just like in the image you can write queries on the left side of the playground and get results on the right part. An explorer tab is also on the right part; which auto-generates queries by just clicking on the desired parameters.</p> <p>Frontend Application querying can be done in 3 different ways:</p> <ol> <li><a href="proxy.php?url=https://thegraph.com/docs/en/querying/querying-from-an-application/#graph-client" rel="noopener noreferrer"><strong>Graph client</strong></a></li> <li><a href="proxy.php?url=https://thegraph.com/docs/en/querying/querying-from-an-application/#apollo-client" rel="noopener noreferrer"><strong>Apollo client</strong></a></li> <li><a href="proxy.php?url=https://thegraph.com/docs/en/querying/querying-from-an-application/#urql" rel="noopener noreferrer"><strong>URQL</strong></a></li> </ol> <p>I prefer to use the Apollo client, and I will use this in the frontend aspect of the crypto savings dapp in my next tutorial.</p> <h2> Conclusion <a></a> </h2> <p>Congratulations on making it to the end of this tutorial!πŸŽ‰ You should now have a good understanding of <em>what subgraphs are</em>, why they are useful, and <em>how to initialize</em>, <em>deploy</em>, and <em>query</em> them. With this knowledge, you can begin creating your subgraphs to interact with various contracts and gain insights into their behavior. Run into a wall? ask away in the comments.</p> <p><a href="proxy.php?url=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%2Fvipawr4p38as7xxm69bd.gif" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fvipawr4p38as7xxm69bd.gif" alt="Its over" width="480" height="270"></a></p> webdev javascript beginners programming Build A Personal Crypto Savings Dapp (Part 1) Adebayo Olamilekan Thu, 29 Feb 2024 03:40:15 +0000 https://dev.to/oleanji/build-your-personal-crypto-savings-dapp-part-1-contract-5g8b https://dev.to/oleanji/build-your-personal-crypto-savings-dapp-part-1-contract-5g8b <p>Having a personal savings app for locking crypto (ether) can be fascinating and peaceful, but for those seeking returns (<em>APY/APR</em>), researching staking platforms becomes crucial to avoid scams. Interested? Let's build it together. Not interested? No harm; learn or critique. Let's Build!!</p> <p><a href="proxy.php?url=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%2F663vttpn0rkpc1014mty.gif" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F663vttpn0rkpc1014mty.gif" alt="pudgy penguinss build" width="480" height="480"></a></p> <h2> <strong>Table of contents</strong> </h2> <ol> <li>Introduction and Prerequisites</li> <li>Contract Initialization</li> <li>Variables, Mappings and Structs</li> <li>Constructor Function</li> <li>Main Functions</li> <li>The Getter Functions</li> <li>Contract Wrap Up</li> <li>Contract Testing</li> <li>Contract Deployment and Verification</li> <li>Conclusion</li> </ol> <h3> <strong>Introduction and Prerequisites</strong> <a></a> </h3> <p>This is the first part of a three-part series of building the savings dapp, In this journey, I'm adopting a backend-first approach, a preference rooted in the advantages it offers like precision in frontend parameters and Optimized development workflow. </p> <p>The following tools and technologies will be used in the writing, test, and deployment of this smart contract: </p> <ul> <li><a href="proxy.php?url=https://soliditylang.org/" rel="noopener noreferrer">Solidity programming language</a></li> <li><a href="proxy.php?url=https://book.getfoundry.sh/" rel="noopener noreferrer">Foundry development toolchain</a></li> </ul> <p>Having an idea of how any the above works will make this more understandable, but if you're a total beginner then fear not, dearest gentle reader [<strong>In Lady Whisledown's Voice</strong>].</p> <p>Feel free to explore the completed contract's repository <a href="proxy.php?url=https://dev.tolink%20to%20the%20repository">here</a> – clone it and follow the steps. Don't hesitate to give the repository a star! πŸ˜‰. Additionally, you can inspect the deployed contract on the Polygon Mumbai Explorer <a href="proxy.php?url=https://mumbai.polygonscan.com/address/0x4b1d98af1af713456c1fc86afed67b94c4648f6d" rel="noopener noreferrer">here</a>.</p> <p>If you wish to try starting from scratch and walk your to the top then, run the following commands to set up the project:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>forge init crypto-saves </code></pre> </div> <p>If the command throws an error, maybe you don't have forge installed on your PC then you can start by following the installation process <a href="proxy.php?url=https://dev.to/oleanji/installing-foundry-toolchain-on-windows-27ml">in a previous tutorial</a> or <a href="proxy.php?url=https://book.getfoundry.sh/getting-started/installation" rel="noopener noreferrer">on the official site</a> .</p> <p>After the initialization of the project, we will then install the <a href="proxy.php?url=https://www.openzeppelin.com/" rel="noopener noreferrer">Openzeppelin contracts</a> library - this gives us some ready-to-use contracts that will be needed later on.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>cd crypto-saves forge install OpenZeppelin/openzeppelin-contracts </code></pre> </div> <p>Then open your project in VS Code with <code>code .</code> In the <code>foundry.toml</code> file in your root directory replace this with the one currently in there;<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>[profile.default] optimizer = true optimizer_runs = 20000 solc_version = '0.8.20' [profile.ci] fuzz-runs = 10_000 [fmt] line_length = 120 </code></pre> </div> <p>Then create a new file in the <code>src</code> folder named <code>CryptoSaves.sol</code>. In this file we are going to write out all the functions and security checks the savings dapps would need; some of the main ones are:</p> <ul> <li> <strong><code>lockEther</code></strong>: To lock the crypto (ether)</li> <li> <strong><code>unlockEther</code></strong>: To unlock your ether after saving</li> <li> <strong><code>extendLockTime</code></strong>: Increases the locking period of a savings</li> <li> <strong><code>withdrawAllEther</code></strong>: Withdraws all your crypto as long as the first lockup time has passed.</li> <li> <strong><code>emergencyWithdraw</code></strong>: Allows you to withdraw your ether as long as the emergency time set has passed.</li> </ul> <p><a href="proxy.php?url=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%2F4zvggohk42278ztwgrso.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F4zvggohk42278ztwgrso.png" alt="Vs code file hierachy" width="262" height="325"></a></p> <h3> <strong>Contract Initialization</strong> <a></a> </h3> <p>To set up the contract, In the <code>CryptoSaves.sol</code> file write the below block of code;<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {Ownable} from "../lib/openzeppelin-contracts/contracts/access/Ownable.sol"; /// @title Crypto Saving Contract /// @author Oleanji /// @notice A contracts that locks funds for a a particular period of time contract CryptoSaves is Ownable(msg.sender) { // Rest of the contract will be written here } </code></pre> </div> <p>The code begins by specifying the license (MIT), and then indicates that we are using a version of the Solidity compiler equal to or greater than 0.8.13 (^0.8.13). This Solidity code defines a contract named <em>CryptoSaves</em> that imports the Ownable contract from the OpenZeppelin library and makes it the parent contract. </p> <p>We are passing the <strong>msg.sender</strong> argument to indicate that the deployer of the contract will become its initial owner.</p> <h3> <strong>Variables, Mappings, and Structs</strong><a></a> </h3> <blockquote> <p>These are essentials in writing the functions for this contract, so next we define them before the main parts of the contract:<br> </p> </blockquote> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> error CannotLockZeroEther(); error LockupIsntLocked(); error UnlockTimeHasNotReached(); error AdditionalMonthsShouldBeMoreThanZero(); error NoLockupHasBeenDone(); event EtherLocked( uint256 indexed id, string name, address owner, uint256 amount, uint256 releaseTime, string lockType ); event EtherUnlocked( uint256 indexed id, string name, address owner, uint256 amount ); event LockupTimeExtended( uint256 indexed id, string name, address owner, uint256 releaseTime ); struct Lockup { uint256 lockId; string name; string lockType; uint256 amount; uint256 releaseTime; bool locked; } mapping(uint256 =&gt; Lockup) public lockups; uint256 public emergencyUnlockTimestamp; uint private lockIdTracker = 0; </code></pre> </div> <p>The five custom <em>error</em> messages are defined at the beginning of the contract, these errors will be thrown when appropriate conditions are not met during contract execution. After Three events are defined:</p> <ul> <li> <strong><code>EtherLocked</code></strong>: Fired upon successful ether lock-up, </li> <li> <strong><code>EtherUnlocked</code></strong>: Emitted when ether is unlocked, </li> <li> <strong><code>LockupTimeExtended</code></strong>: Triggered when extending lockup durations, </li> </ul> <blockquote> <p>Events serve as a mechanism to notify interested parties about significant changes occurring within a smart contract. </p> </blockquote> <p>Next, a struct called Lockup is declared, which contains several fields; This struct represents a single lockup entry, storing information about how much Ether was deposited, when it should be unlocked, and whether it is currently locked or not. [Like a savings box].</p> <p>Following that, a mapping called lockups is created, which maps each lock ID to its corresponding Lockup struct. This allows easy lookups of specific lock entries based on their ID numbers.</p> <p>Two variables are declared next: <em><strong>emergencyUnlockTimestamp</strong></em> and <em><strong>lockIdTracker</strong></em>. emergencyUnlockTimestamp stores the timestamp at which an emergency unlock function becomes available, while lockIdTracker keeps track of the last assigned lock ID number and is used to generate unique IDs for new lockups [Using this in place of Counters.sol].</p> <h3> <strong>Constructor Function</strong> <a></a> </h3> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>constructor(uint256 _months) { lockIdTracker += 1; emergencyUnlockTimestamp = block.timestamp + (_months * 30 days); } </code></pre> </div> <p>The constructor function is a special function that gets executed only once - when the contract is deployed. Here it initializes the contract with a lockup period of _months months. It increments the lockIdTracker and calculates the emergencyUnlockTimestamp based on the input _months. Once set, the emergencyUnlockTimestamp cannot be changed.</p> <h3> <strong>Main Functions</strong> <a></a> </h3> <ol> <li> <strong>LockEther Function</strong>: The <em>lockEther</em> function permits the contract owner to lock ether for a specified duration. Parameters accepted are:</li> </ol> <ul> <li> <strong><code>_months</code></strong>: Specifies the lockup duration in months.</li> <li> <strong><code>_name</code></strong>: Provides a descriptive label for the lockup.</li> <li> <strong><code>_lockType</code></strong>: Represents the type of lockup being initiated.</li> </ul> <p>When invoked with valid inputs, it creates a new lockup entry with a unique ID, computes the release time, and emits an "Ether Locked" event.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>function lockEther( uint256 _months, string memory _name, string memory _lockType ) external payable onlyOwner { if (msg.value &lt;= 0) revert CannotLockZeroEther(); uint256 releaseTime = block.timestamp + (_months * 30 days); uint256 lockId = lockIdTracker; lockups[lockId] = Lockup( lockId, _name, _lockType, msg.value, releaseTime, true ); lockIdTracker += 1; emit EtherLocked( lockId, _name, msg.sender, msg.value, releaseTime, _lockType ); } </code></pre> </div> <ol> <li> <strong>UnlockEther Function</strong>: The <em>unlockEther</em> function unlocks an already locked ether in the contract and sends the ether back to the owner; as long as the unlock time time has passed; It accepts a single parameter: _lockID: the unique identifier for each lockup made in the contract. It also emits an EtherUnlocked event after the ether has been transferred to the owner. </li> </ol> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> function unlockEther(uint256 _lockId) external onlyOwner { if (!lockups[_lockId].locked) revert LockupIsntLocked(); if (block.timestamp &lt; lockups[_lockId].releaseTime) revert UnlockTimeHasNotReached(); uint256 amountToTransfer = lockups[_lockId].amount; lockups[_lockId].amount = 0; lockups[_lockId].locked = false; payable(msg.sender).transfer(amountToTransfer); emit EtherUnlocked( _lockId, lockups[_lockId].name, msg.sender, amountToTransfer ); } </code></pre> </div> <ol> <li> <strong>ExtendLockTime Function</strong>: Sometimes we are just not ready to open our piggy banks, so we extend the day we properly open it to become very rich [like I thought when I was a kid]. This function essentially does the same by accepting the additional months then adding that to the already to the releaseTime, then emitting an LockupTimeExtended event. </li> </ol> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>function extendLockTime( uint256 _additionalMonths, uint256 _lockId ) external onlyOwner { if (_additionalMonths &lt;= 0) revert AdditionalMonthsShouldBeMoreThanZero(); if (!lockups[_lockId].locked) revert LockupIsntLocked(); uint256 newReleaseTime = lockups[_lockId].releaseTime + (_additionalMonths * 30 days); lockups[_lockId].releaseTime = newReleaseTime; emit LockupTimeExtended( _lockId, lockups[_lockId].name, msg.sender, newReleaseTime ); } </code></pre> </div> <h3> <strong>The Getter Functions</strong> <a></a> </h3> <p>The are functions that just return the data from the blockain and do not modify or change the state of the contract also known as view functions.</p> <ol> <li><p><strong><code>getAllLockUps()</code></strong>: Retrieves complete lockup inventory maintained by the contract. Returns an array of Lockup instances, encompassing all entries. Parameterless, designed as a public view function.</p></li> <li><p><strong><code>getLockupDetailsById()</code></strong>: Extracts granular information regarding a specific lockup identified via its unique ID.<br> Accepts a single parameter, _<em>lockId</em>, identifying the target lockup entry.<br> Returns detailed information encapsulating the requested lockup as a Lockup instance.</p></li> </ol> <h3> <strong>Contract Wrap Up</strong> <a></a> </h3> <p>The last part of the smart contract code is a receive function fallback function specifically crafted to accept incoming ether transfers.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>receive() external payable {} </code></pre> </div> <p>After this, the whole smart contract should look like the below, <br> I added some comments to better explain the code.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {Ownable} from "../lib/openzeppelin-contracts/contracts/access/Ownable.sol"; /// @title Crypto Saving Contract /// @author Oleanji /// @notice A contracts that locks funds for a a particular period of time contract CryptoSaves is Ownable(msg.sender) { /// ----------------------------------------------------------------------- /// Errors /// ----------------------------------------------------------------------- error CannotLockZeroEther(); error LockupIsntLocked(); error UnlockTimeHasNotReached(); error AdditionalMonthsShouldBeMoreThanZero(); error NoLockupHasBeenDone(); /// ----------------------------------------------------------------------- /// Events /// ----------------------------------------------------------------------- event EtherLocked( uint256 indexed id, string name, address owner, uint256 amount, uint256 releaseTime, string lockType ); event EtherUnlocked( uint256 indexed id, string name, address owner, uint256 amount ); event LockupTimeExtended( uint256 indexed id, string name, address owner, uint256 releaseTime ); /// ----------------------------------------------------------------------- /// Structs /// ----------------------------------------------------------------------- struct Lockup { uint256 lockId; string name; string lockType; uint256 amount; uint256 releaseTime; bool locked; } /// ----------------------------------------------------------------------- /// Mappings /// ----------------------------------------------------------------------- mapping(uint256 =&gt; Lockup) public lockups; /// ----------------------------------------------------------------------- /// Variables /// ----------------------------------------------------------------------- uint256 public emergencyUnlockTimestamp; uint private lockIdTracker = 0; /// ----------------------------------------------------------------------- /// Constructor /// ----------------------------------------------------------------------- constructor(uint256 _months) { lockIdTracker += 1; emergencyUnlockTimestamp = block.timestamp + (_months * 30 days); } /// ----------------------------------------------------------------------- /// External functions /// ----------------------------------------------------------------------- /// @notice locks your ether for a specific amount of month /// @param _months the number of months to lock the ether for function lockEther( uint256 _months, string memory _name, string memory _lockType ) external payable onlyOwner { if (msg.value &lt;= 0) revert CannotLockZeroEther(); uint256 releaseTime = block.timestamp + (_months * 30 days); uint256 lockId = lockIdTracker; lockups[lockId] = Lockup( lockId, _name, _lockType, msg.value, releaseTime, true ); lockIdTracker += 1; emit EtherLocked( lockId, _name, msg.sender, msg.value, releaseTime, _lockType ); } /// @notice unlocks ether when the unlock date has reached /// @param _lockId the Id of the lockUp you want to unlock function unlockEther(uint256 _lockId) external onlyOwner { if (!lockups[_lockId].locked) revert LockupIsntLocked(); if (block.timestamp &lt; lockups[_lockId].releaseTime) revert UnlockTimeHasNotReached(); uint256 amountToTransfer = lockups[_lockId].amount; lockups[_lockId].amount = 0; lockups[_lockId].locked = false; payable(msg.sender).transfer(amountToTransfer); emit EtherUnlocked( _lockId, lockups[_lockId].name, msg.sender, amountToTransfer ); } /// @notice extends lock time ether when the unlock date has reached /// @param _lockId the Id of the lockUp you want to edit its date /// @param _additionalMonths the number of months to increase the lock up for function extendLockTime( uint256 _additionalMonths, uint256 _lockId ) external onlyOwner { if (_additionalMonths &lt;= 0) revert AdditionalMonthsShouldBeMoreThanZero(); if (!lockups[_lockId].locked) revert LockupIsntLocked(); uint256 newReleaseTime = lockups[_lockId].releaseTime + (_additionalMonths * 30 days); lockups[_lockId].releaseTime = newReleaseTime; emit LockupTimeExtended( _lockId, lockups[_lockId].name, msg.sender, newReleaseTime ); } /// @notice Withdraws all amount in the contract as long as you have locked once function withdrawAllEther() external onlyOwner { uint256 currentId = lockIdTracker; if (currentId == 0 || address(this).balance &lt;= 0) revert NoLockupHasBeenDone(); if (block.timestamp &lt; lockups[1].releaseTime) revert UnlockTimeHasNotReached(); uint256 amountToTransfer = address(this).balance; payable(msg.sender).transfer(amountToTransfer); } /// @notice Withdraws all amount in the contract as long as the emergency lock period has passed function emergencyWithdraw() external onlyOwner { uint256 currentId = lockIdTracker; if (currentId == 0 || address(this).balance &lt;= 0) revert NoLockupHasBeenDone(); if ( emergencyUnlockTimestamp &gt; lockups[currentId].releaseTime &amp;&amp; emergencyUnlockTimestamp &gt; block.timestamp ) revert UnlockTimeHasNotReached(); uint256 amountToTransfer = address(this).balance; payable(msg.sender).transfer(amountToTransfer); } /// @notice Gets all the Lockups created function getAllLockUps() external view returns (Lockup[] memory) { uint256 total = lockIdTracker; Lockup[] memory lockup = new Lockup[](total); for (uint256 i = 1; i &lt; total; i++) { lockup[i] = lockups[i]; } return lockup; } /// @notice Gets specific lock up details /// @param _lockId the Id of the lockUp you want details for function getLockupDetailsById( uint256 _lockId ) external view returns (Lockup memory) { Lockup memory lockDetails = lockups[_lockId]; return (lockDetails); } receive() external payable {} } </code></pre> </div> <p>Run this to build and compile the contract written so far.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>forge build </code></pre> </div> <h3> <strong>Contract Testing</strong> <a></a> </h3> <p>To test the CryptoSaves contract already written we will need to write a test script for this in the test folder named <em>CryptoSaves.t.sol</em>, In this script we will test each of the following:</p> <ul> <li>Creating a lockup using the <strong>lockEther</strong> Function</li> <li>Unlocking a created lockup using the <strong>unlockEther</strong> Function</li> <li>Extending the lockup time for a lockup</li> <li>Getting all Lockups data with the GetAllLockUps() function</li> <li>Getting a single lockup data with the getLockupDetailsById() function</li> <li>Then replicating all the errors listed in the contract.</li> </ul> <p>This is all shown in the below script with more comments to explain each line.</p> <p>Use <code>forge test</code> to run the test script, add a <em>v</em> flag to increase the verbosity i.e for more details from running the test script so I mostly use <br> <code>forge test -vvvv</code><br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; import "forge-std/Test.sol"; import "../src/CryptoSaves.sol"; import "forge-std/console.sol"; contract CryptoSavesCheatsTest is Test { CryptoSaves public cryptoSaves; address alice = vm.addr(0x2); function setUp() public { vm.startPrank(alice); cryptoSaves = new CryptoSaves(8); //using 8 months as my emergency time vm.stopPrank(); } function testLockEther() public { vm.startPrank(alice); /// crediting aka dealing 200 ethers to alice account vm.deal(alice, 200 ether); // first lockup cryptoSaves.lockEther{value: 5 ether}(3, "LockUpOne", "Fees"); assertEq(cryptoSaves.getLockupDetailsById(1).amount, 5e18); // second lockup cryptoSaves.lockEther{value: 50 ether}(6, "LockUpTwo", "Family"); assertEq(cryptoSaves.getLockupDetailsById(2).amount, 50e18); vm.stopPrank(); } function testUnlockEther() public { vm.startPrank(alice); vm.deal(alice, 60 ether); // Locking up 5 ether for 3*30 days cryptoSaves.lockEther{value: 5 ether}(3, "My First LockUp", "Fees"); assertEq(cryptoSaves.getLockupDetailsById(1).amount, 5e18); // Locking up 50 ether for 6*30 days cryptoSaves.lockEther{value: 50 ether}(6, "My Second LockUp", "Travel"); assertEq(cryptoSaves.getLockupDetailsById(2).amount, 50e18); // skips forward into the future to 3*30 days from now to be able to unlock skip(7776001); // unlocks cryptoSaves.unlockEther(1); assertEq(cryptoSaves.getLockupDetailsById(1).locked, false); assertEq(address(alice).balance, 10e18); // skips more forward into the future to 3*30 days // so a total of 6*30 days from now to be able to unlock skip(7776001); //second unlock cryptoSaves.unlockEther(2); assertEq(cryptoSaves.getLockupDetailsById(2).locked, false); assertEq(address(alice).balance, 60e18); vm.stopPrank(); } function testExtendLockTime() public { vm.startPrank(alice); vm.deal(alice, 60 ether); // Locking up 5 ether for 3*30 days cryptoSaves.lockEther{value: 5 ether}(3, "LockUpOne", "Fees"); assertEq(cryptoSaves.getLockupDetailsById(1).amount, 5e18); cryptoSaves.extendLockTime(3, 1); assertGt(cryptoSaves.getLockupDetailsById(1).releaseTime, 7776001); } function testGetAllLockUps() public { vm.startPrank(alice); vm.deal(alice, 60 ether); // third lockup cryptoSaves.lockEther{value: 5 ether}(3, "LockUpOne", "Fees"); // second lockup cryptoSaves.lockEther{value: 7 ether}(6, "LockUpTwo", "Fees"); //third lockup cryptoSaves.lockEther{value: 21 ether}(6, "LockUpThree", "Pets"); //fourth lockup cryptoSaves.lockEther{value: 11 ether}(6, "LockUpFour", "Festivals"); // now check for all lockupdetails //first lockup assertEq(cryptoSaves.getAllLockUps()[1].amount, 5e18); assertEq(cryptoSaves.getAllLockUps()[1].locked, true); //second lockup assertEq(cryptoSaves.getAllLockUps()[2].amount, 7e18); assertEq(cryptoSaves.getAllLockUps()[2].locked, true); //third lockup assertEq(cryptoSaves.getAllLockUps()[4].amount, 11e18); assertEq(cryptoSaves.getAllLockUps()[4].locked, true); vm.stopPrank(); } function testGetLockupDetailsById() public { vm.startPrank(alice); vm.deal(alice, 10 ether); // Locking up 5 ether for 3*30 days cryptoSaves.lockEther{value: 10 ether}(3, "LockUpOne", "Fees"); assertEq(cryptoSaves.getLockupDetailsById(1).amount, 10e18); assertEq(cryptoSaves.getLockupDetailsById(1).locked, true); assertEq(cryptoSaves.getLockupDetailsById(1).lockId, 1); assertGt( cryptoSaves.getLockupDetailsById(1).releaseTime, 3 * 30 * 24 * 60 * 60 ); // the months * days*hrs*min*sec } function testWithdrawAllEther() public { vm.deal(address(cryptoSaves), 4 ether); vm.startPrank(alice); vm.deal(alice, 60 ether); cryptoSaves.lockEther{value: 5 ether}(3, "LockUpOne", "Fees"); assertEq(cryptoSaves.getLockupDetailsById(1).locked, true); skip(7776001); //withdraws all the money in the contract cryptoSaves.withdrawAllEther(); assertEq(address(alice).balance, 64e18); vm.stopPrank(); } function testEmergencyWithdraw() public { vm.deal(address(cryptoSaves), 48 ether); vm.startPrank(alice); vm.deal(alice, 10 ether); cryptoSaves.lockEther{value: 6 ether}(3, "My First LockUp", "Fees"); assertEq(cryptoSaves.getLockupDetailsById(1).amount, 6e18); assertEq( cryptoSaves.getLockupDetailsById(1).amount + address(alice).balance, 10e18 ); // the emergency withdraw time is after 8*30 daysso to to skip intime after then skip(8 * 30 * 24 * 60 * 60 + 1); //withdraws all the money in the contract for emergencies cryptoSaves.emergencyWithdraw(); assertEq(address(alice).balance, 58e18); vm.stopPrank(); } function testCannotLockZeroEther() public { vm.startPrank(alice); vm.expectRevert(CryptoSaves.CannotLockZeroEther.selector); cryptoSaves.lockEther{value: 0 ether}(3, "First Locking", "Pets"); vm.stopPrank(); } function testLockupIsntLocked() public { vm.startPrank(alice); vm.deal(alice, 10 ether); cryptoSaves.lockEther{value: 6 ether}(3, "LockUp", "Fees"); assertEq(cryptoSaves.getLockupDetailsById(1).locked, true); skip(3 * 30 * 24 * 60 * 60 + 1); cryptoSaves.unlockEther(1); vm.expectRevert(CryptoSaves.LockupIsntLocked.selector); cryptoSaves.extendLockTime(1, 1); vm.stopPrank(); } function testUnlockTimeHasNotReached() public { vm.startPrank(alice); vm.deal(alice, 10 ether); cryptoSaves.lockEther{value: 6 ether}(3, "LockUp No1", "Fees"); vm.expectRevert(CryptoSaves.UnlockTimeHasNotReached.selector); cryptoSaves.unlockEther(1); //skip by a month to test if it will go through skip(1 * 30 * 24 * 60 * 60 + 1); vm.expectRevert(CryptoSaves.UnlockTimeHasNotReached.selector); cryptoSaves.withdrawAllEther(); //skip by another month totest if it will go through skip(1 * 30 * 24 * 60 * 60 + 1); vm.expectRevert(CryptoSaves.UnlockTimeHasNotReached.selector); cryptoSaves.emergencyWithdraw(); vm.stopPrank(); } function testAdditionalMonthsShouldBeMoreThanZero() public { vm.startPrank(alice); vm.deal(alice, 10 ether); cryptoSaves.lockEther{value: 6 ether}(3, "My First LockUp", "Fees"); vm.expectRevert( CryptoSaves.AdditionalMonthsShouldBeMoreThanZero.selector ); cryptoSaves.extendLockTime(0, 1); vm.stopPrank(); } function testNoLockupHasBeenDone() public { vm.startPrank(alice); assertEq(address(cryptoSaves).balance, 0); vm.expectRevert(CryptoSaves.NoLockupHasBeenDone.selector); cryptoSaves.emergencyWithdraw(); vm.stopPrank(); } } </code></pre> </div> <h3> <strong>Contract Deployment and Verification</strong> <a></a> </h3> <p>This is the last part of building this project, here we will deploy and verify the contract to the polygon Mumbai test network, Before that we need to write our deployment script which essentially shows the deployment of the <em>CryptoSaves contract</em>, along with an eight-month emergency lock period.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; import {Script} from "../lib/forge-std/src/Script.sol"; import {console} from "../lib/forge-std/src/console.sol"; import {CryptoSaves} from "../src/CryptoSaves.sol"; contract CryptoSavesScript is Script { function run() external { vm.startBroadcast(); console.log( "....Deploying CryptoSaves deployer with 8 months emergency lock period.... " ); CryptoSaves cryptoSave = new CryptoSaves(8); console.log("CryptoSaves Contract Deployed To:", address(cryptoSave)); vm.stopBroadcast(); } } </code></pre> </div> <p>To run this script, we will use the below command which not only deploys the contract but also verifies it on the polygon mumbai test network.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>forge script script/CryptoSaves.s.sol:CryptoSavesScript --rpc-url RPC_URL --private-key YOUR_PRIVATE_KEY --broadcast --verify --etherscan-api-key YOUR_POLYGONSCAN_API -vvvv --gas-price 60 --legacy </code></pre> </div> <p>To use this command you will need:</p> <ul> <li><p>RPC_URL : This is a url needed to deploy the contract and you can get it from different providers, but in this tutorial I am using <a href="proxy.php?url=https://www.ankr.com/" rel="noopener noreferrer">Ankr</a>.</p></li> <li><p>YOUR_PRIVATE_KEY: This is the key of the account you want to use for deployment which shouldn't be shared with anyone. You can get some mumbai test token to use for deployment <a href="proxy.php?url=https://faucet.polygon.technology/?__cf_chl_tk=Bl5kZFvhMT8jIwFPCLfAH_h_rnM5NDHvUvZUZE481yg-1709131140-0.0-1469" rel="noopener noreferrer">here</a></p></li> <li><p>YOUR_POLYGONSCAN_API: In order to verify the contract you will need an api key from <a href="proxy.php?url=https://polygonscan.com/" rel="noopener noreferrer">polygon</a>, you can get that by creating and account then an api key.</p></li> </ul> <p>After getting all the keys and replacing them you can now run the command to deploy and verify your crypto saves contract.</p> <p><a href="proxy.php?url=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%2Fffq6sv6429cu25f21h4o.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fffq6sv6429cu25f21h4o.png" alt="deployed result" width="633" height="172"></a></p> <p>From the result obtained here, the contract was deployed to:</p> <ul> <li>Address: 0x4b1D98AF1af713456c1fC86Afed67b94c4648f6d</li> <li>Polygon Mumbai Link: <a href="proxy.php?url=https://mumbai.polygonscan.com/address/0x4b1d98af1af713456c1fc86afed67b94c4648f6d" rel="noopener noreferrer">CryptoSaves Contract</a> </li> </ul> <h3> <strong>Conclusion</strong> <a></a> </h3> <p>This marks the end of our journey in this tutorial. I hope you found this helpful and resourceful, have any questions? leave a comment.</p> <p>Now you have a fully deployed and verified personal crypto savings contract. Feels good right!</p> <p><a href="proxy.php?url=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%2Fqkuvdve5lxcsg1tzxjgh.gif" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fqkuvdve5lxcsg1tzxjgh.gif" alt="Yesss" width="478" height="410"></a></p> <p><strong>Note</strong>: The code for this project is <a href="proxy.php?url=https://github.com/OleanjiKingCode/CryptoSaves--Contract" rel="noopener noreferrer">here</a>.</p> webdev tutorial blockchain javascript 11 Ways to Improve Website Performance in Next.js Webpages Adebayo Olamilekan Mon, 21 Aug 2023 19:06:44 +0000 https://dev.to/oleanji/11-ways-to-improve-website-performance-in-nextjs-webpages-3i5e https://dev.to/oleanji/11-ways-to-improve-website-performance-in-nextjs-webpages-3i5e <p>In today's rapidly evolving digital landscape, optimizing your website's performance and enhancing user experience are paramount to capturing user engagement and achieving higher search engine rankings. This comprehensive guide delves into essential strategies and techniques tailored for Next.js applications to amplify performance and deliver an exceptional browsing experience. Let's embark on this journey to elevate your website's performance and user satisfaction!</p> <h3> Performance Testing Prerequisites </h3> <p>Before testing your website's performance using Lighthouse:</p> <ol> <li><p><strong>Incognito Mode</strong>: Test in incognito mode without browser extensions to ensure accurate results.</p></li> <li><p><strong>Build Your Site</strong>: Run <code>yarn build</code> or <code>npm run build</code> to build your Next.js application.</p></li> <li><p><strong>Production Build</strong>: Only test the performance of a production build, not a development version. Start your server with <code>yarn start</code> or <code>npm run start</code>.</p></li> </ol> <h3> 1. Server-side Rendering (SSR) </h3> <p>Leverage Next.js's inbuilt Server-side Rendering (SSR) capabilities to minimize Time to First Paint (TTFP) and enrich user experience. SSR generates initial HTML on the server, resulting in reduced client-side rendering time.</p> <h3> 2. Code Splitting and Lazy Loading </h3> <p>Divide your code into smaller units through dynamic imports (<code>import()</code>) to load components on-demand. This approach minimizes initial load times by deferring the loading of non-critical components. Consider a blog site where comment sections or large images are loaded only when necessary.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight jsx"><code><span class="k">import</span> <span class="nx">dynamic</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">next/dynamic</span><span class="dl">'</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">LazyComponent</span> <span class="o">=</span> <span class="nf">dynamic</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="k">import</span><span class="p">(</span><span class="dl">'</span><span class="s1">./LazyComponent</span><span class="dl">'</span><span class="p">));</span> <span class="kd">function</span> <span class="nf">HomePage</span><span class="p">()</span> <span class="p">{</span> <span class="k">return </span><span class="p">(</span> <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span> <span class="si">{</span><span class="cm">/* Other content */</span><span class="si">}</span> <span class="p">&lt;</span><span class="nc">LazyComponent</span> <span class="p">/&gt;</span> <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span> <span class="p">);</span> <span class="p">}</span> </code></pre> </div> <h3> 3. Optimize Images </h3> <p>Optimize images for modern formats like WebP and adopt responsive images with Next.js's <code>&lt;Image&gt;</code> component. This reduces file sizes and improves load times.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight jsx"><code><span class="k">import</span> <span class="nx">Image</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">next/image</span><span class="dl">'</span><span class="p">;</span> <span class="p">&lt;</span><span class="nc">Image</span> <span class="na">src</span><span class="p">=</span><span class="s">"/images/my-image.webp"</span> <span class="na">alt</span><span class="p">=</span><span class="s">"An optimized image"</span> <span class="na">width</span><span class="p">=</span><span class="si">{</span><span class="mi">1200</span><span class="si">}</span> <span class="na">height</span><span class="p">=</span><span class="si">{</span><span class="mi">800</span><span class="si">}</span> <span class="na">layout</span><span class="p">=</span><span class="s">"responsive"</span> <span class="p">/&gt;</span> </code></pre> </div> <h3> 4. Bundle Analysis </h3> <p>Employ tools like <code>webpack-bundle-analyzer</code> to dissect your bundles and identify heavy dependencies. Trim unnecessary code and optimize bundles for faster loading.</p> <h3> 5. Minification and Compression </h3> <p>Minify CSS and JavaScript to eliminate unnecessary characters. Enable Gzip or Brotli compression on your server to shrink transfer sizes.</p> <h3> 6. Reduce Third-Party Dependencies </h3> <p>Prune third-party libraries judiciously, ensuring they align with performance goals. Over-reliance on external dependencies can introduce performance bottlenecks.</p> <h3> 7. Monitoring </h3> <p>Regularly gauge performance with tools like Lighthouse, PageSpeed Insights, and real user monitoring. Track progress and address issues promptly.</p> <h3> 8. Optimizing Third-Party Scripts </h3> <p>Use Next.js's Script component to optimize loading for third-party JavaScript. Fetch and execute scripts as needed, avoiding delays in page rendering.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight jsx"><code><span class="k">import</span> <span class="nx">Script</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">next/script</span><span class="dl">'</span><span class="p">;</span> <span class="kd">function</span> <span class="nf">IndexPage</span><span class="p">()</span> <span class="p">{</span> <span class="k">return </span><span class="p">(</span> <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nc">Script</span> <span class="na">strategy</span><span class="p">=</span><span class="s">"afterInteractive"</span> <span class="na">src</span><span class="p">=</span><span class="s">"https://www.googletagmanager.com/gtag/js?id=123"</span> <span class="p">/&gt;</span> <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span> <span class="p">);</span> <span class="p">}</span> </code></pre> </div> <h3> 9. Alt Text for Images </h3> <p>Enhance accessibility with meaningful <code>alt</code> attributes for images. This ensures screen readers convey the image's purpose to visually impaired users.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight jsx"><code><span class="k">import</span> <span class="nx">Image</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">next/image</span><span class="dl">'</span><span class="p">;</span> <span class="p">&lt;</span><span class="nc">Image</span> <span class="na">src</span><span class="p">=</span><span class="s">"/images/my-image.webp"</span> <span class="na">alt</span><span class="p">=</span><span class="s">"An optimized image"</span> <span class="na">width</span><span class="p">=</span><span class="si">{</span><span class="mi">1200</span><span class="si">}</span> <span class="na">height</span><span class="p">=</span><span class="si">{</span><span class="mi">800</span><span class="si">}</span> <span class="na">layout</span><span class="p">=</span><span class="s">"responsive"</span> <span class="p">/&gt;</span> </code></pre> </div> <h3> 10. Remove Unused Dependencies </h3> <p>Regularly prune unused dependencies from your project to minimize bloat and enhance performance.</p> <h3> 11. Font Optimization using Next Fonts </h3> <p>Leverage Next.js's built-in Automatic Webfont Optimization. By inlining font CSS at build time, you eliminate the extra round trip required to fetch font declarations. This optimization leads to improvements in First Contentful Paint (FCP) and Largest Contentful Paint (LCP), two key Core Web Vitals metrics.</p> <p>Another notable approach is the use of next/font, which automatically optimizes fonts (including custom fonts) and removes external network requests for enhanced privacy and performance.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight jsx"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">Inter</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">next/font/google</span><span class="dl">'</span> <span class="c1">// If loading a variable font, you don't need to specify the font weight</span> <span class="kd">const</span> <span class="nx">inter</span> <span class="o">=</span> <span class="nc">Inter</span><span class="p">({</span> <span class="na">subsets</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">latin</span><span class="dl">'</span><span class="p">]</span> <span class="p">})</span> <span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nf">MyApp</span><span class="p">({</span> <span class="nx">Component</span><span class="p">,</span> <span class="nx">pageProps</span> <span class="p">})</span> <span class="p">{</span> <span class="k">return </span><span class="p">(</span> <span class="p">&lt;</span><span class="nt">main</span> <span class="na">className</span><span class="p">=</span><span class="si">{</span><span class="nx">inter</span><span class="p">.</span><span class="nx">className</span><span class="si">}</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nc">Component</span> <span class="si">{</span><span class="p">...</span><span class="nx">pageProps</span><span class="si">}</span> <span class="p">/&gt;</span> <span class="p">&lt;/</span><span class="nt">main</span><span class="p">&gt;</span> <span class="p">)</span> <span class="p">}</span> </code></pre> </div> <h3> Conclusion </h3> <p>By adhering to these strategies, you can transform your Next.js application into a high-performing platform that delights users and appeals to search engines. Continuous monitoring and refinement are key to upholding your website's standards and delivering a seamless user experience. For further insights, explore the <a href="proxy.php?url=https://nextjs.org/learn/seo/improve" rel="noopener noreferrer">Improving your Core Web Vitals</a> guide on the Next.js website. </p> <p>Embrace the journey of optimization and witness the transformation of your website's performance!</p> nextjs beginners javascript tutorial Earn free tokens from Axia Adebayo Olamilekan Wed, 26 Apr 2023 23:41:52 +0000 https://dev.to/oleanji/earn-free-tokens-from-axia-438m https://dev.to/oleanji/earn-free-tokens-from-axia-438m <p><strong>Axia Ecosystem</strong> is a revolutionary platform that seeks to bring creators and their audience closer through innovative incentive motivation. At <strong>Axia</strong>, we understand the challenges that content creators face in reaching their target audience and earning a sustainable income. That's why we have created a platform that rewards users for engaging with content creators. </p> <p>Axia Ecosystem is built on Lens Protocol, Polygon Blockchain, and Question Gen AI. It is an idea birthed during the Season 3 of buildspace nights-and-weekends program, which seeks to empower anyone to build and launch their own ideas.</p> <p>To attract users to our platform, we are offering two ways to collect tokens:</p> <ul> <li><p>Uploading an article to <strong>Axia Ecosystem</strong> </p></li> <li><p>Passing a random quiz. </p></li> </ul> <p>In this article, we will discuss these two ways in detail and explain how you can start collecting tokens on our platform.</p> <h2> <strong>Section 1</strong>: Upload an Article to Axia Ecosystem </h2> <p>Axia is offering <strong>ONE</strong> Polygon Mumbai token to anyone who uploads an article to the platform. This is a great opportunity for content creators/developers to earn cryptocurrency while showcasing their work to a wider audience. By uploading an article to Axia, you'll also gain exposure to potential new fans and supporters (surely when Axia ecosystem launches πŸŽ‰).</p> <p>To upload an article on Axia Ecosystem: </p> <ol> <li>Simply go to <a href="proxy.php?url=https://axai-ecosystem.vercel.app/" rel="noopener noreferrer">Axia</a> </li> </ol> <p><a href="proxy.php?url=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%2F1q6lc73pxsem14jeoc98.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F1q6lc73pxsem14jeoc98.png" alt="Axia" width="800" height="345"></a></p> <ol> <li><p>Connect your wallet to Axia on the polygon network (either testnet or mainnent)</p></li> <li><p>Go to the articles page; now click on <code>Create New Article</code></p></li> </ol> <p><a href="proxy.php?url=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%2F9rtq645u9p4wdbtnmu6o.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F9rtq645u9p4wdbtnmu6o.png" alt="Article" width="800" height="366"></a></p> <ol> <li>Write your story and then <strong>post</strong> </li> </ol> <p><a href="proxy.php?url=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%2Fxu4ko1q7tq6fmpgx87iq.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fxu4ko1q7tq6fmpgx87iq.png" alt="Imaon" width="800" height="449"></a></p> <p><a href="proxy.php?url=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%2Fu4sdlndk4w22q4j3zlor.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fu4sdlndk4w22q4j3zlor.png" alt="In" width="800" height="449"></a></p> <p><em>Note: Add a low res image to boost the transaction</em></p> <p>There would be 3 transaction needed to be signed this is using the postSig lens function, (we apologize for the discomfort)</p> <ol> <li>Collect Reward πŸŽ‰πŸŽ‰</li> </ol> <p><a href="proxy.php?url=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%2Fwrzjime5wc7lw49k7gp8.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fwrzjime5wc7lw49k7gp8.png" alt="scription" width="627" height="360"></a><br> First, change your network to Mumbai by clicking the button, then click again to claim.</p> <p>The link of the contract used for claiming tokens is <a href="proxy.php?url=https://mumbai.polygonscan.com/address/0x19C59a273eBc46F1c63b7D3b74C8b82D54C20F6c#readContract" rel="noopener noreferrer">AxiaMumbaiDisperser</a></p> <p>Section 2: Pass a Random Quiz on Axia Ecosystem</p> <p>In addition to earning a Polygon Mumbai token for uploading an article to Axia Ecosystem, users can earn an additional token by passing a random quiz on the platform. </p> <p>To take the quiz on Axia Ecosystem:</p> <ol> <li>Briefly read the story for which the quiz is about (in the articles page).</li> </ol> <p><a href="proxy.php?url=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%2Fbuqaw4blzposydfpnsh6.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fbuqaw4blzposydfpnsh6.png" alt="Ition" width="410" height="456"></a></p> <ol> <li>Navigate to the "Random Quiz" section and follow the instructions provided. The quiz is administered by Question Gen AI and consists of a set of multiple-choice questions. </li> </ol> <p><a href="proxy.php?url=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%2Flk8xe1tijtdtbkc0boz3.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Flk8xe1tijtdtbkc0boz3.png" alt="Imripion" width="800" height="388"></a></p> <ol> <li>Once you pass the quiz (with a score of 4/10 or higher), you'll earn another Polygon Mumbai token by clicking on the 'Collect your rewards' button.</li> </ol> <p><a href="proxy.php?url=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%2Fg0vwpu7xincrw4ohbf75.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fg0vwpu7xincrw4ohbf75.png" alt="n" width="800" height="346"></a></p> <p>We hope this is very simple and straightforward to follow and understand then try out Axia Ecosystem and engage with its services. Whether you're a content creator or someone just wants to earn some tokens. </p> <p>Thank you for considering Axia Ecosystem. We look forward to seeing you on the platform!</p> <p>Hopefully, we launch and this would change from test tokens to real ones, πŸ˜‰.</p> buildspace javascript tutorial beginners Protecting Yourself from DeFi Rug Pulls: Tips and Tricks πŸ”’πŸ’ΈπŸ’‘ Adebayo Olamilekan Sun, 09 Apr 2023 17:48:01 +0000 https://dev.to/oleanji/protecting-yourself-from-defi-rug-pulls-tips-and-tricks-2ee4 https://dev.to/oleanji/protecting-yourself-from-defi-rug-pulls-tips-and-tricks-2ee4 <p>DeFi has gained immense popularity over the past year, with more and more people turning to decentralized finance platforms to trade, lend, and borrow crypto assets. However, with the increasing popularity of DeFi, there has also been a rise in rug pulls - a term used to describe fraudulent projects that disappear with investors' funds. In this article, we'll explore what rug pulls are and how you can avoid and detect them.</p> <h2> <strong>What is a Rug Pull?</strong> </h2> <p>A rug pull is a fraudulent practice that is typically carried out by the creators of a DeFi project. The creators lure investors with the promise of high returns and then disappear with the investors' funds. Rug pulls can happen in several ways, but they usually involve a fake project that is designed to look legitimate.</p> <h2> How to Avoid DeFi Rug Pulls </h2> <ul> <li><p>Research the Project: The first step in avoiding rug pulls is to research the DeFi project thoroughly. Check the project's website, read the whitepaper, and understand how the project works. Look for information about the team behind the project and their experience in the industry.</p></li> <li><p>Check the Code: Check the project's code on the blockchain. Look for any vulnerabilities or potential risks. If you're not an experienced developer, you can seek the help of a technical expert.</p></li> <li><p>Analyze the Tokenomics: Look at the project's tokenomics - how the tokens are distributed, how they are used, and how they will be used in the future. Check for any red flags such as a large percentage of tokens held by the project creators.</p></li> <li><p>Examine the Liquidity: Check the liquidity of the project's tokens. If the liquidity is low, it could be a sign that the project is not attracting many investors. However, if the liquidity is too high, it could be a sign that the project creators are trying to pump up the price of the token before pulling the rug.</p></li> <li><p>Avoid Projects with Anonymous Teams: If the team behind the project is anonymous or cannot be verified, it's best to avoid investing in the project. Anonymity can make it difficult to hold the team accountable if something goes wrong.</p></li> <li><p>Look for Audits: Check if the project has been audited by a reputable third-party auditor. Audits can help identify potential vulnerabilities and reduce the risk of rug pulls.</p></li> </ul> <h2> How to Detect DeFi Rug Pulls </h2> <ul> <li><p>Sudden Drop in Price: One of the most common signs of a rug pull is a sudden drop in the token's price. If the price of the token drops significantly and suddenly, it could be a sign that the project creators have pulled the rug.</p></li> <li><p>Project Website Disappears: If the project's website suddenly disappears, it's a clear sign that something is not right. The website could have been taken down by the project creators or the authorities.</p></li> <li><p>Social Media Accounts Disappear: If the project's social media accounts suddenly disappear or go silent, it's a sign that something is wrong. The project creators may be trying to hide from investors or authorities.</p></li> <li><p>Abnormal Trading Volume: If there is a sudden spike in trading volume followed by a drop in price, it could be a sign that the project creators are trying to create hype around the project before pulling the rug.</p></li> <li><p>Locked Liquidity: If the liquidity of the project's tokens is suddenly locked or removed, it's a sign that the project creators are trying to prevent investors from selling their tokens.</p></li> <li><p>Fake News: If the project creators release fake news or false information to create hype around the project, it's a clear sign that something is not right.</p></li> </ul> <h2> Conclusion </h2> <p>DeFi rug pulls are a real threat, and investors need to be cautious, I hope you found this article helpful in understanding the concept of rug pulls and how to avoid them in DeFi projects. Remember to always conduct thorough research before investing in any DeFi project and be cautious of high returns or promises of quick profits. With these precautions in mind, you can navigate the DeFi world safely and potentially reap the rewards of this exciting and rapidly evolving industry.</p> blockchain web3 defi beginners Exploring Modifiers in Solidity Adebayo Olamilekan Thu, 16 Mar 2023 21:21:05 +0000 https://dev.to/oleanji/exploring-modifiers-in-solidity-50ei https://dev.to/oleanji/exploring-modifiers-in-solidity-50ei <p>Solidity is a popular programming language used to write smart contracts on the Ethereum blockchain. Smart contracts are self-executing agreements with the terms of the agreement between buyer and seller being directly written into lines of code. Modifiers are a feature of Solidity that allow developers to add extra checks and conditions to functions in their contracts.</p> <p>In this article, we will explore what modifiers are, how they work, and why they are useful in Solidity contracts.</p> <h2> What are Modifiers? </h2> <p>Modifiers are pieces of code that can be added to Solidity contracts to modify the behavior of functions. A modifier is like a function in that it has a name, parameters, and code that is executed when it is called. However, a modifier does not have a return value, and it is not called directly by other functions.</p> <p>Instead, a modifier is used to modify the behavior of other functions in the contract. When a function is modified by a modifier, the modifier's code is executed first. If the modifier's code passes all of its checks and conditions, then the <code>_</code> symbol in the modifier code is replaced with the code of the modified function. This means that the modified function's code will be inserted in place of the <code>_</code> symbol, and then the entire modified code will be executed as if it were a single function.</p> <h2> How do Modifiers work? </h2> <p>Modifiers are defined using the <code>modifier</code> keyword, followed by the name of the modifier and any parameters it takes. The code for the modifier is then placed inside curly braces <code>{}</code>. Here's an example of a simple modifier:</p> <p>Solidity<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>modifier onlyOwner { require(msg.sender == owner); _; } </code></pre> </div> <p>In this example, we define a modifier called <code>onlyOwner</code> that checks if the address of the sender is equal to the owner of the contract. If the check passes, the <code>_</code> symbol indicates where the code of the modified function will be inserted. In this case, the modifier is used to restrict access to a function so that only the owner of the contract can call it.</p> <p>To use a modifier in a function, you simply add the modifier's name to the function definition, like this:</p> <p>Soldity<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>function withdraw() public onlyOwner { // function code here } </code></pre> </div> <p>In this example, we use the <code>onlyOwner</code> modifier to restrict access to the <code>withdraw</code> function. When the <code>withdraw</code> function is called, the code for the <code>onlyOwner</code> modifier is executed first. If the check passes, the <code>_</code> symbol is replaced with the code for the <code>withdraw</code> function, and the entire modified code is executed.</p> <h2> Why are Modifiers useful? </h2> <p>Modifiers are useful in Solidity contracts for several reasons:</p> <ol> <li><p>Reducing code duplication: Modifiers allow you to write complex checks and conditions once and then reuse them in multiple functions throughout the contract. This reduces the amount of code you need to write and makes your contract more readable and maintainable.</p></li> <li><p>Improving contract security: Modifiers can be used to add extra checks and conditions to functions, which can help prevent common security vulnerabilities like reentrancy attacks or incorrect access control. By using modifiers to add these checks and conditions, you can make your contract more secure and less prone to bugs or exploits.</p></li> <li><p>Simplifying function definitions: By moving complex checks and conditions to modifiers, you can simplify the definitions of your functions. This makes your functions easier to read and understand, and can help you avoid mistakes or errors when writing new code.</p></li> <li><p>Enforcing consistent behavior: Modifiers allow you to enforce consistent behavior across multiple functions in your contract. For example, you can use a modifier to ensure that only the contract owner can call certain functions, or to check that</p></li> </ol> <p>In conclusion, modifiers are an essential tool for Solidity developers to ensure that their contracts behave in the desired way and prevent unauthorized access. They provide a simple yet powerful way to apply conditions to functions and can help make your code more reusable, readable, and secure.</p> webdev web3 beginners tutorial Connect Wallet App using WAGMI and Tailwind CSS Adebayo Olamilekan Sun, 01 Jan 2023 13:22:19 +0000 https://dev.to/oleanji/connect-wallet-app-using-wagmi-and-tailwind-css-2db1 https://dev.to/oleanji/connect-wallet-app-using-wagmi-and-tailwind-css-2db1 <p>In Web3 applications connecting to a user's wallet is one of the most important aspects of the application, as it allows users to interact with the app, like signing transactions, getting profile data through the user's address, etc.</p> <p>Connecting a wallet to a decentralized application is like logging into a traditional web2 application. Therefore, in building a web3 application this part is essential and If it isn't built well it can reduce the user's experience when using your application.</p> <p>Using applications like <a href="proxy.php?url=https://www.rainbowkit.com/" rel="noopener noreferrer">Rainbow kit</a> in your dapp does a wonderful job of connecting the user's wallet, it also has different connection options, but the code is abstracted away and developers sometimes don't know how to implement this functionality.</p> <p>This is a tutorial for building a connect wallet application you can use in your web3 projects.</p> <h2> Building a connect wallet for your decentralized application. </h2> <p>To build this connect wallet application, these technologies are needed;</p> <ul> <li><p><a href="proxy.php?url=https://wagmi.sh/" rel="noopener noreferrer">WAGMI</a>: It is a collection of React Hooks containing everything you need to start working with Ethereum.</p></li> <li><p><a href="proxy.php?url=https://tailwindcss.com/" rel="noopener noreferrer">Tailwind CSS</a>: It is a CSS framework that is used to rapidly build modern websites without ever leaving your HTML.</p></li> <li><p><a href="proxy.php?url=https://react-icons.github.io/react-icons" rel="noopener noreferrer">React-icons:</a> This package is used to get icons to use in the interface of the application.</p></li> <li><p><a href="proxy.php?url=https://headlessui.com/" rel="noopener noreferrer">Headless-UI</a>: This contains components that are completely unstyled, and fully accessible, which were designed to integrate beautifully with Tailwind CSS.</p></li> <li><p><a href="proxy.php?url=https://docs.ethers.org/v5/" rel="noopener noreferrer">Ethers</a> Js: It's a library that is used for interacting with the Ethereum Blockchain and its ecosystem.</p></li> </ul> <p>The complete application can be found <a href="proxy.php?url=http://connect-wallet-drab.vercel.app/" rel="noopener noreferrer">here</a> along with the <a href="proxy.php?url=https://github.com/OleanjiKingCode/Connect-wallet" rel="noopener noreferrer">GitHub repo</a> to this project.</p> <p>The finished look of the application can be downloaded <a href="proxy.php?url=https://github.com/OleanjiKingCode/Connect-wallet/blob/main/public/full%20video.mp4" rel="noopener noreferrer">here</a>.</p> <h3> <strong>Let's get started!!! πŸš€πŸš€</strong> </h3> <ol> <li> <p>Create a new project and open PowerShell/ terminal pointing to that location and run the following:<br> </p> <pre class="highlight shell"><code>npx create-next-app@latest connect-wallet-app <span class="nb">cd </span>connect-wallet-app npm <span class="nb">install</span> <span class="nt">-D</span> tailwindcss postcss autoprefixer npx tailwindcss init <span class="nt">-p</span> npm <span class="nb">install</span> @headlessui/react wagmi ethers react-icons code <span class="nb">.</span> </code></pre> <p>The above will install <a href="proxy.php?url=https://nextjs.org/" rel="noopener noreferrer">Next Js</a> and other dependencies needed for this tutorial and then opens the project in your code editor.</p> <p><em>For this tutorial, choose No for both the typescript and ESlint options, when creating the next app.</em></p> </li> <li><p>Configure your tailwind CSS installation, steps on this can be found in their <a href="proxy.php?url=https://tailwindcss.com/docs/guides/nextjs" rel="noopener noreferrer">docs</a>.</p></li> <li> <p>Create a new folder in the root of your project and rename it to <strong><em>src</em></strong> and move the pages folder into it. Then create a new sub-folder inside the src folder named <strong><em>config.</em></strong></p> <p>Your project tree should look similar to this πŸ‘‡πŸ½</p> <p><a href="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1672001396916%2F9e6661d9-9ae3-4dc2-8106-cff89589fc8c.png%2520align%3D" class="article-body-image-wrapper"><img src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1672001396916%2F9e6661d9-9ae3-4dc2-8106-cff89589fc8c.png%2520align%3D" width="800" height="400"></a></p> </li> <li> <p>To start using wagmi in our application we need a client, therefore a need to configure it.</p> <p>Inside the config subfolder create a file named <strong><em>wagmi.js</em></strong> and write this inside<br> </p> <pre class="highlight javascript"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">WalletConnectConnector</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">wagmi/connectors/walletConnect</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">MetaMaskConnector</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">wagmi/connectors/metaMask</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">chain</span><span class="p">,</span> <span class="nx">configureChains</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">wagmi</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">publicProvider</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">wagmi/providers/public</span><span class="dl">"</span><span class="p">;</span> <span class="c1">// using only 2 chains with WAGMI; ETH and Matic(Polygon)</span> <span class="kd">const</span> <span class="nx">chainArray</span> <span class="o">=</span> <span class="p">[</span><span class="nx">chain</span><span class="p">.</span><span class="nx">polygon</span><span class="p">,</span> <span class="nx">chain</span><span class="p">.</span><span class="nx">mainnet</span><span class="p">];</span> <span class="k">export</span> <span class="kd">const</span> <span class="p">{</span> <span class="nx">chains</span><span class="p">,</span> <span class="nx">provider</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">configureChains</span><span class="p">(</span><span class="nx">chainArray</span><span class="p">,</span> <span class="p">[</span> <span class="nf">publicProvider</span><span class="p">(),</span> <span class="p">]);</span> <span class="k">export</span> <span class="kd">const</span> <span class="nx">connectors</span> <span class="o">=</span> <span class="p">[</span> <span class="k">new</span> <span class="nc">MetaMaskConnector</span><span class="p">({</span> <span class="nx">chains</span><span class="p">,</span> <span class="na">options</span><span class="p">:</span> <span class="p">{</span> <span class="na">shimDisconnect</span><span class="p">:</span> <span class="kc">true</span> <span class="p">}</span> <span class="p">}),</span> <span class="k">new</span> <span class="nc">WalletConnectConnector</span><span class="p">({</span> <span class="nx">chains</span><span class="p">,</span> <span class="na">options</span><span class="p">:</span> <span class="p">{</span> <span class="na">qrcode</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="p">},</span> <span class="p">}),</span> <span class="p">];</span> </code></pre> <p>For this tutorial only Metamask and WalletConnect wallets are implemented, you can take this further to accept multiple wallets.</p> </li> <li> <p>We need to wrap the page components in a wagmi client, this is done in the <strong><em>_app.js</em></strong> file found in the pages subfolder.<br> </p> <pre class="highlight javascript"><code><span class="k">import</span> <span class="dl">"</span><span class="s2">../../styles/globals.css</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">createClient</span><span class="p">,</span> <span class="nx">WagmiConfig</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">wagmi</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">connectors</span><span class="p">,</span> <span class="nx">provider</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">../config/wagmi</span><span class="dl">"</span><span class="p">;</span> <span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nf">App</span><span class="p">({</span> <span class="nx">Component</span><span class="p">,</span> <span class="nx">pageProps</span> <span class="p">})</span> <span class="p">{</span> <span class="kd">const</span> <span class="nx">client</span> <span class="o">=</span> <span class="nf">createClient</span><span class="p">({</span> <span class="na">autoConnect</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="na">connectors</span><span class="p">:</span> <span class="nx">connectors</span><span class="p">,</span> <span class="nx">provider</span><span class="p">,</span> <span class="p">});</span> <span class="k">return </span><span class="p">(</span> <span class="o">&lt;</span><span class="nx">WagmiConfig</span> <span class="nx">client</span><span class="o">=</span><span class="p">{</span><span class="nx">client</span><span class="p">}</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Component</span> <span class="p">{...</span><span class="nx">pageProps</span><span class="p">}</span> <span class="sr">/</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/WagmiConfig</span><span class="err">&gt; </span> <span class="p">);</span> <span class="p">}</span> </code></pre> <p>This ends the configuration needed to start building the main part of this application.</p> </li> <li> <p>Running <code>yarn dev</code> or <code>npm run dev</code> to start the application would still show the default Next js page gotten from the installation. Get rid of that code and put this part in πŸ‘‡πŸ½(Part1)<br> </p> <pre class="highlight javascript"><code><span class="c1">// All the needed imports for this application</span> <span class="k">import</span> <span class="nx">Head</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">next/head</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">useState</span><span class="p">,</span> <span class="nx">useEffect</span><span class="p">,</span> <span class="nx">Fragment</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">Listbox</span><span class="p">,</span> <span class="nx">Transition</span><span class="p">,</span> <span class="nx">Dialog</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">@headlessui/react</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">RiArrowDownSLine</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react-icons/ri</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">useNetwork</span><span class="p">,</span> <span class="nx">useAccount</span><span class="p">,</span> <span class="nx">useConnect</span><span class="p">,</span> <span class="nx">useDisconnect</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">wagmi</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">utils</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">ethers</span><span class="dl">"</span><span class="p">;</span> <span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nf">Home</span><span class="p">()</span> <span class="p">{</span> <span class="c1">//The necessary data needed to use the two chains </span> <span class="kd">const</span> <span class="nx">NETWORK_DATA</span> <span class="o">=</span> <span class="p">[</span> <span class="p">{</span> <span class="na">id</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">image</span><span class="p">:</span> <span class="dl">"</span><span class="s2">/polygon.png</span><span class="dl">"</span><span class="p">,</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Polygon</span><span class="dl">"</span><span class="p">,</span> <span class="na">isActive</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="na">chainNoHex</span><span class="p">:</span> <span class="mi">137</span><span class="p">,</span> <span class="na">chainId</span><span class="p">:</span> <span class="nx">utils</span><span class="p">.</span><span class="nf">hexValue</span><span class="p">(</span><span class="mi">137</span><span class="p">),</span> <span class="na">chainName</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Polygon Mainnet</span><span class="dl">"</span><span class="p">,</span> <span class="na">nativeCurrency</span><span class="p">:</span> <span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">MATIC</span><span class="dl">"</span><span class="p">,</span> <span class="na">symbol</span><span class="p">:</span> <span class="dl">"</span><span class="s2">MATIC</span><span class="dl">"</span><span class="p">,</span> <span class="na">decimals</span><span class="p">:</span> <span class="mi">18</span> <span class="p">},</span> <span class="na">rpcUrls</span><span class="p">:</span> <span class="p">[</span><span class="dl">"</span><span class="s2">https://polygon-rpc.com/</span><span class="dl">"</span><span class="p">],</span> <span class="na">blockExplorerUrls</span><span class="p">:</span> <span class="p">[</span><span class="dl">"</span><span class="s2">https://polygonscan.com</span><span class="dl">"</span><span class="p">],</span> <span class="p">},</span> <span class="p">{</span> <span class="na">id</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="na">image</span><span class="p">:</span> <span class="dl">"</span><span class="s2">/eth.png</span><span class="dl">"</span><span class="p">,</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Ethereum</span><span class="dl">"</span><span class="p">,</span> <span class="na">isActive</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span> <span class="na">chainId</span><span class="p">:</span> <span class="nx">utils</span><span class="p">.</span><span class="nf">hexValue</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="na">chainNoHex</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">chainName</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Ethereum Mainnet</span><span class="dl">"</span><span class="p">,</span> <span class="na">nativeCurrency</span><span class="p">:</span> <span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Ether</span><span class="dl">"</span><span class="p">,</span> <span class="na">symbol</span><span class="p">:</span> <span class="dl">"</span><span class="s2">ETH</span><span class="dl">"</span><span class="p">,</span> <span class="na">decimals</span><span class="p">:</span> <span class="mi">18</span> <span class="p">},</span> <span class="na">rpcUrls</span><span class="p">:</span> <span class="p">[</span><span class="dl">"</span><span class="s2">https://api.mycryptoapi.com/eth</span><span class="dl">"</span><span class="p">],</span> <span class="na">blockExplorerUrls</span><span class="p">:</span> <span class="p">[</span><span class="dl">"</span><span class="s2">https://etherscan.io</span><span class="dl">"</span><span class="p">],</span> <span class="p">},</span> <span class="p">];</span> <span class="c1">// states used throughtout this project</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">currentNetwork</span><span class="p">,</span> <span class="nx">setCurrentNetwork</span><span class="p">]</span> <span class="o">=</span> <span class="nf">useState</span><span class="p">(</span><span class="nx">NETWORK_DATA</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span> <span class="c1">// this sets the network used</span> <span class="kd">const</span> <span class="p">{</span> <span class="nx">chain</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">useNetwork</span><span class="p">();</span> <span class="c1">// this gets the chain the user connected to in the app</span> <span class="kd">const</span> <span class="p">{</span> <span class="na">isConnected</span><span class="p">:</span> <span class="nx">isUserConnected</span><span class="p">,</span> <span class="nx">address</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">useAccount</span><span class="p">();</span> <span class="c1">// get a boolean for the connection of a user and also their address</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">isOpen</span><span class="p">,</span> <span class="nx">setIsOpen</span><span class="p">]</span> <span class="o">=</span> <span class="nf">useState</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">walletDetailsOpen</span><span class="p">,</span> <span class="nx">setWalletDetails</span><span class="p">]</span> <span class="o">=</span> <span class="nf">useState</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">switchOpen</span><span class="p">,</span> <span class="nx">setSwitchOpen</span><span class="p">]</span> <span class="o">=</span> <span class="nf">useState</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span> <span class="kd">const</span> <span class="p">{</span> <span class="nx">disconnect</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">useDisconnect</span><span class="p">();</span> <span class="c1">// this is function used to disconnect a user after connection</span> <span class="p">...</span> <span class="p">}</span> </code></pre> <p>The images referred to in the code above can be gotten from <a href="proxy.php?url=https://github.com/OleanjiKingCode/Connect-wallet/tree/main/public" rel="noopener noreferrer">here</a>.</p> </li> <li> <p>This next part of the code; shows the various functions used in the application like the switch network functionality, wallet details modal, etc.<br> </p> <pre class="highlight javascript"><code><span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nf">Home</span><span class="p">()</span> <span class="p">{</span> <span class="p">...</span> <span class="c1">// this checks if the user is connected to the right chain, if not then it opens a modal for you to switch to the right wallet.</span> <span class="nf">useEffect</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="nc">CheckNetwork</span><span class="p">();</span> <span class="p">},</span> <span class="p">[</span><span class="nx">isUserConnected</span><span class="p">,</span> <span class="nx">currentNetwork</span><span class="p">]);</span> <span class="kd">const</span> <span class="nx">CheckNetwork</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="k">if </span><span class="p">(</span><span class="nx">isUserConnected</span> <span class="o">&amp;&amp;</span> <span class="nx">chain</span><span class="p">?.</span><span class="nx">id</span> <span class="o">!==</span> <span class="nx">currentNetwork</span><span class="p">.</span><span class="nx">chainNoHex</span><span class="p">)</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">chain</span><span class="p">?.</span><span class="nx">id</span><span class="p">,</span> <span class="nx">currentNetwork</span><span class="p">.</span><span class="nx">chainId</span><span class="p">);</span> <span class="nf">openSwitchOpen</span><span class="p">();</span> <span class="p">}</span> <span class="p">};</span> <span class="kd">function</span> <span class="nf">closeModal</span><span class="p">()</span> <span class="p">{</span> <span class="nf">setIsOpen</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span> <span class="p">}</span> <span class="kd">function</span> <span class="nf">openModal</span><span class="p">()</span> <span class="p">{</span> <span class="nf">setIsOpen</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span> <span class="p">}</span> <span class="kd">function</span> <span class="nf">closeWalletDetails</span><span class="p">()</span> <span class="p">{</span> <span class="nf">setWalletDetails</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span> <span class="p">}</span> <span class="kd">function</span> <span class="nf">openWalletDetails</span><span class="p">()</span> <span class="p">{</span> <span class="nf">setWalletDetails</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span> <span class="p">}</span> <span class="kd">function</span> <span class="nf">closeSwitchOpen</span><span class="p">()</span> <span class="p">{</span> <span class="nf">setSwitchOpen</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span> <span class="p">}</span> <span class="kd">function</span> <span class="nf">openSwitchOpen</span><span class="p">()</span> <span class="p">{</span> <span class="nf">setSwitchOpen</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span> <span class="p">}</span> <span class="c1">// Logout function</span> <span class="kd">const</span> <span class="nx">logout</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="nf">disconnect</span><span class="p">();</span> <span class="nf">closeWalletDetails</span><span class="p">();</span> <span class="p">};</span> <span class="kd">const</span> <span class="p">{</span> <span class="nx">connectors</span><span class="p">,</span> <span class="nx">connect</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">useConnect</span><span class="p">({</span> <span class="nf">onSuccess</span><span class="p">()</span> <span class="p">{</span> <span class="nf">closeModal</span><span class="p">();</span> <span class="p">},</span> <span class="p">});</span> <span class="kd">const</span> <span class="nx">getText</span> <span class="o">=</span> <span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="k">if </span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="dl">"</span><span class="s2">Wallet Details</span><span class="dl">"</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="dl">"</span><span class="s2">Connect Wallet</span><span class="dl">"</span><span class="p">;</span> <span class="p">};</span> <span class="c1">//Switch Network Functionality</span> <span class="kd">const</span> <span class="nx">handleSwitchNetwork</span> <span class="o">=</span> <span class="k">async </span><span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="kd">const</span> <span class="p">{</span> <span class="nx">chainId</span><span class="p">,</span> <span class="nx">chainName</span><span class="p">,</span> <span class="nx">rpcUrls</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">currentNetwork</span><span class="p">;</span> <span class="k">try</span> <span class="p">{</span> <span class="k">await</span> <span class="nb">window</span><span class="p">.</span><span class="nx">ethereum</span><span class="p">?.</span><span class="nf">request</span><span class="p">({</span> <span class="na">method</span><span class="p">:</span> <span class="dl">"</span><span class="s2">wallet_switchEthereumChain</span><span class="dl">"</span><span class="p">,</span> <span class="na">params</span><span class="p">:</span> <span class="p">[{</span> <span class="nx">chainId</span> <span class="p">}],</span> <span class="p">});</span> <span class="nf">closeSwitchOpen</span><span class="p">();</span> <span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">switchError</span><span class="p">)</span> <span class="p">{</span> <span class="kd">const</span> <span class="nx">err</span> <span class="o">=</span> <span class="nx">switchError</span><span class="p">;</span> <span class="k">if </span><span class="p">(</span><span class="nx">err</span><span class="p">.</span><span class="nx">code</span> <span class="o">===</span> <span class="mi">4902</span><span class="p">)</span> <span class="p">{</span> <span class="k">try</span> <span class="p">{</span> <span class="k">await</span> <span class="nb">window</span><span class="p">.</span><span class="nx">ethereum</span><span class="p">?.</span><span class="nf">request</span><span class="p">({</span> <span class="na">method</span><span class="p">:</span> <span class="dl">"</span><span class="s2">wallet_addEthereumChain</span><span class="dl">"</span><span class="p">,</span> <span class="na">params</span><span class="p">:</span> <span class="p">[</span> <span class="p">{</span> <span class="nx">chainId</span><span class="p">,</span> <span class="nx">chainName</span><span class="p">,</span> <span class="nx">rpcUrls</span><span class="p">,</span> <span class="p">},</span> <span class="p">],</span> <span class="p">});</span> <span class="nf">closeSwitchOpen</span><span class="p">();</span> <span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">addError</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="kc">null</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="k">return</span> <span class="kc">null</span><span class="p">;</span> <span class="p">};</span> <span class="p">...</span> <span class="p">}</span> </code></pre> <p>All the above code so far shows the function, variables, and logic needed for the connect wallet application.</p> <p>The <strong>handleSwitchNetwork</strong> function is called upon when the user isn't connected to the selected network and what this function does is get the current networks info (chainId, name, and rpcUrls) which is used to re-connect the user to that network.</p> </li> <li> <p>Viewing the output of your project now won't show anything, since there is no frontend code written.</p> <p>The frontend code is divided into two apects:</p> <p>-&gt; The <strong><em>Network dropdown</em></strong> and <strong><em>connect wallet</em></strong> button</p> <p>-&gt; The modals</p> <p>The first part πŸ‘‡πŸ½<br> </p> <pre class="highlight javascript"><code><span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nf">Home</span><span class="p">()</span> <span class="p">{</span> <span class="p">...</span> <span class="o">&lt;&gt;</span> <span class="o">&lt;</span><span class="nx">Head</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">title</span><span class="o">&gt;</span><span class="nx">Connect</span> <span class="nx">Wallet</span> <span class="nx">App</span><span class="o">&lt;</span><span class="sr">/title</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">meta</span> <span class="nx">name</span><span class="o">=</span><span class="dl">"</span><span class="s2">description</span><span class="dl">"</span> <span class="nx">content</span><span class="o">=</span><span class="dl">"</span><span class="s2">Connect wallet app</span><span class="dl">"</span> <span class="o">/&gt;</span> <span class="o">&lt;</span><span class="nx">meta</span> <span class="nx">name</span><span class="o">=</span><span class="dl">"</span><span class="s2">viewport</span><span class="dl">"</span> <span class="nx">content</span><span class="o">=</span><span class="dl">"</span><span class="s2">width=device-width, initial-scale=1</span><span class="dl">"</span> <span class="o">/&gt;</span> <span class="o">&lt;</span><span class="nx">link</span> <span class="nx">rel</span><span class="o">=</span><span class="dl">"</span><span class="s2">icon</span><span class="dl">"</span> <span class="nx">href</span><span class="o">=</span><span class="dl">"</span><span class="s2">/favicon.ico</span><span class="dl">"</span> <span class="o">/&gt;</span> <span class="o">&lt;</span><span class="sr">/Head</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">w-full</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="s2">`w-full h-screen flex items-center text-center justify-center bg-orange-300 `</span><span class="p">}</span> <span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2"> w-72 mr-6</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Listbox</span> <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">currentNetwork</span><span class="p">}</span> <span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="nx">setCurrentNetwork</span><span class="p">}</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">relative mt-1</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Listbox</span><span class="p">.</span><span class="nx">Button</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">relative w-full cursor-default rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">span</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">flex items-center </span><span class="dl">"</span><span class="o">&gt;</span> <span class="p">{</span><span class="dl">"</span><span class="s2"> </span><span class="dl">"</span><span class="p">}</span> <span class="o">&lt;</span><span class="nx">img</span> <span class="nx">src</span><span class="o">=</span><span class="p">{</span><span class="nx">currentNetwork</span><span class="p">.</span><span class="nx">image</span><span class="p">}</span> <span class="nx">alt</span><span class="o">=</span><span class="p">{</span><span class="nx">currentNetwork</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span> <span class="nx">width</span><span class="o">=</span><span class="dl">"</span><span class="s2">34px</span><span class="dl">"</span> <span class="o">/&gt;</span> <span class="p">{</span><span class="nx">currentNetwork</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span> <span class="o">&lt;</span><span class="sr">/span</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">span</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">RiArrowDownSLine</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">h-5 w-5 text-gray-400</span><span class="dl">"</span> <span class="nx">aria</span><span class="o">-</span><span class="nx">hidden</span><span class="o">=</span><span class="dl">"</span><span class="s2">true</span><span class="dl">"</span> <span class="o">/&gt;</span> <span class="o">&lt;</span><span class="sr">/span</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Listbox.Button</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">Transition</span> <span class="k">as</span><span class="o">=</span><span class="p">{</span><span class="nx">Fragment</span><span class="p">}</span> <span class="nx">leave</span><span class="o">=</span><span class="dl">"</span><span class="s2">transition ease-in duration-100</span><span class="dl">"</span> <span class="nx">leaveFrom</span><span class="o">=</span><span class="dl">"</span><span class="s2">opacity-100</span><span class="dl">"</span> <span class="nx">leaveTo</span><span class="o">=</span><span class="dl">"</span><span class="s2">opacity-0</span><span class="dl">"</span> <span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Listbox</span><span class="p">.</span><span class="nx">Options</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm</span><span class="dl">"</span><span class="o">&gt;</span> <span class="p">{</span><span class="nx">NETWORK_DATA</span><span class="p">.</span><span class="nf">map</span><span class="p">((</span><span class="nx">person</span><span class="p">,</span> <span class="nx">personIdx</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">(</span> <span class="o">&lt;</span><span class="nx">Listbox</span><span class="p">.</span><span class="nx">Option</span> <span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">personIdx</span><span class="p">}</span> <span class="nx">className</span><span class="o">=</span><span class="p">{({</span> <span class="nx">active</span> <span class="p">})</span> <span class="o">=&gt;</span> <span class="s2">`relative cursor-default select-none py-2 px-4 </span><span class="p">${</span> <span class="nx">active</span> <span class="p">?</span> <span class="dl">"</span><span class="s2">bg-amber-100 text-amber-900</span><span class="dl">"</span> <span class="p">:</span> <span class="dl">"</span><span class="s2">text-gray-900</span><span class="dl">"</span> <span class="p">}</span><span class="s2">`</span> <span class="p">}</span> <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">person</span><span class="p">}</span> <span class="o">&gt;</span> <span class="p">{({</span> <span class="nx">selected</span> <span class="p">})</span> <span class="o">=&gt;</span> <span class="p">(</span> <span class="o">&lt;&gt;</span> <span class="o">&lt;</span><span class="nx">span</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="s2">`flex items-center w-full text-left </span><span class="p">${</span> <span class="nx">selected</span> <span class="p">?</span> <span class="dl">"</span><span class="s2">font-medium</span><span class="dl">"</span> <span class="p">:</span> <span class="dl">"</span><span class="s2">font-normal</span><span class="dl">"</span> <span class="p">}</span><span class="s2">`</span><span class="p">}</span> <span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">img</span> <span class="nx">src</span><span class="o">=</span><span class="p">{</span><span class="nx">person</span><span class="p">.</span><span class="nx">image</span><span class="p">}</span> <span class="nx">alt</span><span class="o">=</span><span class="p">{</span><span class="nx">person</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span> <span class="nx">width</span><span class="o">=</span><span class="dl">"</span><span class="s2">34px</span><span class="dl">"</span> <span class="o">/&gt;</span> <span class="p">{</span><span class="nx">person</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span> <span class="o">&lt;</span><span class="sr">/span</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/</span><span class="err">&gt; </span> <span class="p">)}</span> <span class="o">&lt;</span><span class="sr">/Listbox.Option</span><span class="err">&gt; </span> <span class="p">))}</span> <span class="o">&lt;</span><span class="sr">/Listbox.Options</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Transition</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Listbox</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">type</span><span class="o">=</span><span class="dl">"</span><span class="s2">button</span><span class="dl">"</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">isUserConnected</span> <span class="p">?</span> <span class="nx">openWalletDetails</span> <span class="p">:</span> <span class="nx">openModal</span><span class="p">}</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">rounded-lg bg-black bg-opacity-20 px-4 py-2 text-center text-sm font-medium text-white hover:bg-opacity-30 </span><span class="dl">"</span> <span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="p">{</span><span class="nf">getText</span><span class="p">(</span><span class="nx">isUserConnected</span><span class="p">)}</span><span class="o">&lt;</span><span class="sr">/p</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/button</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span><span class="p">...</span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/</span><span class="err">&gt; </span> <span class="p">);</span> <span class="p">}</span> </code></pre> <p>The above code should show this output (a dropdown and a button).</p> <p><a href="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1672004196563%2F59aa1b98-3270-4775-a2e6-a7392fe2766a.png%2520align%3D" class="article-body-image-wrapper"><img src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1672004196563%2F59aa1b98-3270-4775-a2e6-a7392fe2766a.png%2520align%3D" width="800" height="400"></a></p> </li> <li> <p>There are 3 modals needed for this application as seen in the GIF result of the application; the select wallets modal, the switch network modal and the wallet details modal.</p> <p><strong>Select Wallet modal</strong> is used to choose between the different wallet connectors (metamask and walletconnect).</p> <p><a href="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1672004518772%2Fedbc874f-1a6d-43b2-b06f-039118f5618a.png%2520align%3D" class="article-body-image-wrapper"><img src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1672004518772%2Fedbc874f-1a6d-43b2-b06f-039118f5618a.png%2520align%3D" width="800" height="400"></a><br> </p> <pre class="highlight javascript"><code><span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nf">Home</span><span class="p">()</span> <span class="p">{</span> <span class="p">...</span> <span class="k">return </span><span class="p">(</span> <span class="p">...</span> <span class="o">&lt;</span><span class="nx">Transition</span> <span class="nx">appear</span> <span class="nx">show</span><span class="o">=</span><span class="p">{</span><span class="nx">isOpen</span><span class="p">}</span> <span class="k">as</span><span class="o">=</span><span class="p">{</span><span class="nx">Fragment</span><span class="p">}</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Dialog</span> <span class="k">as</span><span class="o">=</span><span class="dl">"</span><span class="s2">div</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">relative z-10</span><span class="dl">"</span> <span class="nx">onClose</span><span class="o">=</span><span class="p">{</span><span class="nx">closeModal</span><span class="p">}</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">fixed inset-0 overflow-y-auto</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">flex min-h-full items-center justify-center p-4 text-center</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Dialog</span><span class="p">.</span><span class="nx">Panel</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">w-full max-w-md transform ease-in-out duration-300 overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Dialog</span><span class="p">.</span><span class="nx">Title</span> <span class="k">as</span><span class="o">=</span><span class="dl">"</span><span class="s2">h3</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">text-lg font-medium leading-6 text-gray-900</span><span class="dl">"</span> <span class="o">&gt;</span> <span class="nx">Connect</span> <span class="nx">Your</span> <span class="nx">Wallet</span> <span class="o">&lt;</span><span class="sr">/Dialog.Title</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">mt-2 mx-3</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">p</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">text-sm text-gray-500</span><span class="dl">"</span><span class="o">&gt;</span> <span class="nx">Choose</span> <span class="k">from</span> <span class="nx">the</span> <span class="nx">following</span> <span class="o">&lt;</span><span class="sr">/p</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="p">{</span><span class="nx">connectors</span><span class="p">.</span><span class="nf">map</span><span class="p">((</span><span class="nx">connector</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">(</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">index</span><span class="p">}</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="o">=&gt;</span> <span class="nf">connect</span><span class="p">({</span> <span class="nx">connector</span> <span class="p">})}</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">border-2 rounded-lg my-3 cursor-pointer border-gray-300 w-full text-black px-2 py-3 hover:bg-gray-200 hover:text-gray-800</span><span class="dl">"</span> <span class="o">&gt;</span> <span class="p">{</span><span class="nx">connector</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="p">))}</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">mt-4</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">type</span><span class="o">=</span><span class="dl">"</span><span class="s2">button</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">inline-flex justify-center rounded-md border border-transparent bg-red-100 px-4 py-2 text-sm font-medium text-red-900 hover:bg-red-200 </span><span class="dl">"</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">closeModal</span><span class="p">}</span> <span class="o">&gt;</span> <span class="nx">Cancel</span> <span class="o">&lt;</span><span class="sr">/button</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Dialog.Panel</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Dialog</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Transition</span><span class="err">&gt; </span><span class="p">...</span> <span class="p">)</span> <span class="p">}</span> </code></pre> <p><strong>Switch network modal</strong> is used to switch from a wrong network to the chosen selected network.</p> <p><a href="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1672004568755%2Fa4cf6c13-448d-45e9-b7f9-c6fc57786841.png%2520align%3D" class="article-body-image-wrapper"><img src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1672004568755%2Fa4cf6c13-448d-45e9-b7f9-c6fc57786841.png%2520align%3D" width="800" height="400"></a><br> </p> <pre class="highlight javascript"><code><span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nf">Home</span><span class="p">()</span> <span class="p">{</span> <span class="p">...</span> <span class="k">return </span><span class="p">(</span> <span class="p">...</span> <span class="o">&lt;</span><span class="nx">Transition</span> <span class="nx">appear</span> <span class="nx">show</span><span class="o">=</span><span class="p">{</span><span class="nx">switchOpen</span><span class="p">}</span> <span class="k">as</span><span class="o">=</span><span class="p">{</span><span class="nx">Fragment</span><span class="p">}</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Dialog</span> <span class="k">as</span><span class="o">=</span><span class="dl">"</span><span class="s2">div</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">relative z-10</span><span class="dl">"</span> <span class="nx">onClose</span><span class="o">=</span><span class="p">{</span><span class="nx">closeSwitchOpen</span><span class="p">}</span> <span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">fixed inset-0 overflow-y-auto</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">flex min-h-full items-center justify-center p-4 text-center</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Dialog</span><span class="p">.</span><span class="nx">Panel</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">w-full max-w-lg transform ease-in-out duration-300 overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Dialog</span><span class="p">.</span><span class="nx">Title</span> <span class="k">as</span><span class="o">=</span><span class="dl">"</span><span class="s2">h3</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">text-lg font-medium leading-6 mb-3 text-gray-900</span><span class="dl">"</span> <span class="o">&gt;</span> <span class="nx">Switch</span> <span class="nx">Network</span> <span class="o">&lt;</span><span class="sr">/Dialog.Title</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">flex items-center justify-between</span><span class="dl">"</span><span class="o">&gt;</span> <span class="nx">You</span> <span class="nx">need</span> <span class="nx">to</span> <span class="k">switch</span> <span class="nx">the</span> <span class="nx">nework</span> <span class="nx">to</span> <span class="p">{</span><span class="nx">currentNetwork</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2"> flex justify-between mt-4</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">type</span><span class="o">=</span><span class="dl">"</span><span class="s2">button</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">inline-flex justify-center rounded-md border border-transparent bg-green-100 px-4 py-2 text-sm font-medium text-green-900 hover:bg-green-200 </span><span class="dl">"</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">handleSwitchNetwork</span><span class="p">}</span> <span class="o">&gt;</span> <span class="nx">Switch</span> <span class="o">&lt;</span><span class="sr">/button</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">type</span><span class="o">=</span><span class="dl">"</span><span class="s2">button</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">inline-flex justify-center rounded-md border border-transparent bg-red-100 px-4 py-2 text-sm font-medium text-red-900 hover:bg-red-200 </span><span class="dl">"</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">closeSwitchOpen</span><span class="p">}</span> <span class="o">&gt;</span> <span class="nx">Cancel</span> <span class="o">&lt;</span><span class="sr">/button</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Dialog.Panel</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Dialog</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Transition</span><span class="err">&gt; </span><span class="p">...</span> <span class="p">)</span> <span class="p">}</span> </code></pre> <p><strong>Wallet Details Modal</strong> is used to a brief details of the connect address, (you can improve on this in your project).</p> <p><a href="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1672004701756%2Fe134356c-1904-46b0-a8d5-74dd1576584a.png%2520align%3D" class="article-body-image-wrapper"><img src="proxy.php?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1672004701756%2Fe134356c-1904-46b0-a8d5-74dd1576584a.png%2520align%3D" width="800" height="400"></a><br> </p> <pre class="highlight javascript"><code><span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nf">Home</span><span class="p">()</span> <span class="p">{</span> <span class="p">...</span> <span class="k">return </span><span class="p">(</span> <span class="p">...</span> <span class="o">&lt;</span><span class="nx">Transition</span> <span class="nx">appear</span> <span class="nx">show</span><span class="o">=</span><span class="p">{</span><span class="nx">walletDetailsOpen</span><span class="p">}</span> <span class="k">as</span><span class="o">=</span><span class="p">{</span><span class="nx">Fragment</span><span class="p">}</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Dialog</span> <span class="k">as</span><span class="o">=</span><span class="dl">"</span><span class="s2">div</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">relative z-10</span><span class="dl">"</span> <span class="nx">onClose</span><span class="o">=</span><span class="p">{</span><span class="nx">closeWalletDetails</span><span class="p">}</span> <span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">fixed inset-0 overflow-y-auto</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">flex min-h-full items-center justify-center p-4 text-center</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Dialog</span><span class="p">.</span><span class="nx">Panel</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">w-full max-w-lg transform ease-in-out duration-300 overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Dialog</span><span class="p">.</span><span class="nx">Title</span> <span class="k">as</span><span class="o">=</span><span class="dl">"</span><span class="s2">h3</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">text-lg font-medium leading-6 mb-3 text-gray-900</span><span class="dl">"</span> <span class="o">&gt;</span> <span class="nx">Wallet</span> <span class="nx">Details</span> <span class="o">&lt;</span><span class="sr">/Dialog.Title</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">flex items-center justify-between</span><span class="dl">"</span><span class="o">&gt;</span> <span class="nx">Your</span> <span class="nx">Address</span><span class="p">:</span> <span class="o">&lt;</span><span class="nx">span</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">text-orange-500</span><span class="dl">"</span><span class="o">&gt;</span> <span class="p">{</span><span class="nx">address</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/span</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">flex items-center text-left</span><span class="dl">"</span><span class="o">&gt;</span> <span class="nx">Network</span><span class="p">:</span> <span class="o">&lt;</span><span class="nx">span</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">text-orange-500 px-3</span><span class="dl">"</span><span class="o">&gt;</span> <span class="p">{</span><span class="dl">"</span><span class="s2"> </span><span class="dl">"</span><span class="p">}</span> <span class="p">{</span><span class="nx">currentNetwork</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span> <span class="o">&lt;</span><span class="sr">/span</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">flex items-center text-left</span><span class="dl">"</span><span class="o">&gt;</span> <span class="nx">Scan</span><span class="p">:{</span><span class="dl">"</span><span class="s2"> </span><span class="dl">"</span><span class="p">}</span> <span class="o">&lt;</span><span class="nx">a</span> <span class="nx">href</span><span class="o">=</span><span class="p">{</span><span class="s2">`</span><span class="p">${</span><span class="nx">currentNetwork</span><span class="p">.</span><span class="nx">blockExplorerUrls</span><span class="p">[</span><span class="mi">0</span><span class="p">]}</span><span class="s2">/address/</span><span class="p">${</span><span class="nx">address</span><span class="p">}</span><span class="s2">`</span><span class="p">}</span> <span class="nx">target</span><span class="o">=</span><span class="dl">"</span><span class="s2">_blank</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">px-5 text-orange-500</span><span class="dl">"</span> <span class="o">&gt;</span> <span class="nx">View</span> <span class="nx">your</span> <span class="nx">assets</span> <span class="nx">here</span><span class="p">{</span><span class="dl">"</span><span class="s2"> </span><span class="dl">"</span><span class="p">}</span> <span class="o">&lt;</span><span class="sr">/a</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">flex justify-between mt-4</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">type</span><span class="o">=</span><span class="dl">"</span><span class="s2">button</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">inline-flex justify-center rounded-md border border-transparent bg-red-100 px-4 py-2 text-sm font-medium text-red-900 hover:bg-red-200 </span><span class="dl">"</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">logout</span><span class="p">}</span> <span class="o">&gt;</span> <span class="nx">Disconnect</span> <span class="o">&lt;</span><span class="sr">/button</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">type</span><span class="o">=</span><span class="dl">"</span><span class="s2">button</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">inline-flex justify-center rounded-md border border-transparent bg-red-100 px-4 py-2 text-sm font-medium text-red-900 hover:bg-red-200 </span><span class="dl">"</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">closeWalletDetails</span><span class="p">}</span> <span class="o">&gt;</span> <span class="nx">Cancel</span> <span class="o">&lt;</span><span class="sr">/button</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Dialog.Panel</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Dialog</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Transition</span><span class="err">&gt; </span><span class="p">...</span> <span class="p">)</span> <span class="p">}</span> </code></pre> </li> </ol> <p>Run your application if it's not already running using <code>yarn dev</code> or <code>npm run dev</code>. This would show your full application working, awesome!! πŸŽ‰πŸš€.</p> <p>You now have a connect wallet app example which can be used in your upcoming web3 projects. Build great and fun stuff 😁.</p> emptystring 8 CSS Frameworks to create wonderful websites. Adebayo Olamilekan Sun, 18 Dec 2022 20:46:53 +0000 https://dev.to/oleanji/8-css-frameworks-to-create-wonderful-websites-1md7 https://dev.to/oleanji/8-css-frameworks-to-create-wonderful-websites-1md7 <p>Using CSS for styling can get tedious for developers as we progress and build sophisticated websites, we need something with less code and more functionality (styling). </p> <p>This is why CSS frameworks are built and used, here is a list of Eight (8) best frameworks:</p> <ul> <li> <a href="proxy.php?url=https://mui.com/" rel="noopener noreferrer">Material UI</a> Material UI (MUI) is said to offer a comprehensive suite of UI tools to help you ship new features faster. Material UI is used by big organizations such as; Spotify, Unity, Nasa, Netflix e.t.c</li> </ul> <p>To Install MUI<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>npm install @mui/material @emotion/react @emotion/styled </code></pre> </div> <p><a href="proxy.php?url=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%2Folmznpozxmh4o3yrn4pq.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Folmznpozxmh4o3yrn4pq.png" alt="MUI" width="800" height="360"></a><em>MUI Homepage</em></p> <ul> <li> <a href="proxy.php?url=https://get.foundation/" rel="noopener noreferrer">Foundation</a> The most advanced responsive front-end framework in the world. Foundation is a family of responsive front-end frameworks that make it easy to design beautiful responsive websites, apps and emails that look amazing on any device.(From their official website).Foundation is used by big organizations such as; Disney, Samsung, Adobe, National Geographic, e.t.c</li> </ul> <p>To Install<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>npm install foundation-sites //or// yarn add foundation-sites </code></pre> </div> <p><a href="proxy.php?url=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%2F70bu64babsmyxx2xa489.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F70bu64babsmyxx2xa489.png" alt="Foundation" width="800" height="393"></a><em>Foundation Homepage</em></p> <ul> <li> <a href="proxy.php?url=https://bulma.io/" rel="noopener noreferrer">Bulma</a> Bulma is a free, open-source framework that provides ready-to-use frontend components that you can easily combine to build responsive web interfaces.CSS Knowledge is not needed when using bulma.</li> </ul> <p>To Install<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>npm install bulma </code></pre> </div> <p><a href="proxy.php?url=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%2Fvnhhpun1oq7t0nmujqz6.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fvnhhpun1oq7t0nmujqz6.png" alt="Bulma" width="800" height="393"></a><em>Bulma homepage</em></p> <ul> <li> <a href="proxy.php?url=https://tailwindcss.com/" rel="noopener noreferrer">Tailwind CSS</a> Tailwind CSS rapidly builds modern websites without ever leaving your HTML. This is interesting as you just write styles in classes of div tags, awesome right?!</li> </ul> <p>To install<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>npm install -D tailwindcss npx tailwindcss init </code></pre> </div> <p><a href="proxy.php?url=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%2Fzqi78z93xnl2m931f3e3.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fzqi78z93xnl2m931f3e3.png" alt="css" width="800" height="396"></a><em>Tailwind Homepage</em></p> <ul> <li> <a href="proxy.php?url=https://getbootstrap.com/" rel="noopener noreferrer">Bootstrap</a> Bootstrap is a powerful, extensible, and feature-packed frontend toolkit. With Bootstrap you can build and customize with Sass, utilize prebuilt grid system and components, and bring projects to life with powerful JavaScript plugins.</li> </ul> <p>To install<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>npm i [email protected] </code></pre> </div> <p><a href="proxy.php?url=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%2Fqiqs2xypdc9aju8caqeu.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fqiqs2xypdc9aju8caqeu.png" alt="bootstrap" width="800" height="394"></a><em>Bootstrap Homepage</em></p> <ul> <li> <a href="proxy.php?url=https://chakra-ui.com/" rel="noopener noreferrer">Chakra UI</a> Chakra UI is a simple, modular and accessible component library that gives you the building blocks you need to build your React applications. With Chakra UI you spend less time writing UI code and more time building a great experience for your customers.</li> </ul> <p>To install<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion or yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion or pnpm add @chakra-ui/react @emotion/react @emotion/styled framer-motion </code></pre> </div> <p><a href="proxy.php?url=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%2F4jqkykp5gampsbliq4cn.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F4jqkykp5gampsbliq4cn.png" alt="chakra" width="800" height="366"></a><em>Chakra UI homepage</em></p> <ul> <li> <a href="proxy.php?url=https://headlessui.com/" rel="noopener noreferrer">Headless UI</a> Headless UI has completely unstyled, fully accessible UI components, designed to integrate beautifully with Tailwind CSS. This is also created by tailwind Labs</li> </ul> <p>To Install<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>npm install @headlessui/react </code></pre> </div> <p><a href="proxy.php?url=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%2Fq3dcijk7vv0dngay9gg9.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fq3dcijk7vv0dngay9gg9.png" alt="headless ui" width="800" height="393"></a><em>Headless UI Homepage</em></p> <ul> <li> <a href="proxy.php?url=https://semantic-ui.com/" rel="noopener noreferrer">Semantic UI</a> Semantic is a development framework that helps create beautiful, responsive layouts using human-friendly HTML.</li> </ul> <p>To Install<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>npm install semantic-ui --save cd semantic/ gulp build </code></pre> </div> <p><a href="proxy.php?url=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%2Fw6f05yfhitp4cy662uit.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fw6f05yfhitp4cy662uit.png" alt="semantic" width="800" height="357"></a><em>Semantic UI Homepage</em></p> <p>There are lots more that are also good to build super websites, but the trick to choosing the best is... <em>no trick</em>, just go with the one you feel will work with you well after thorough research.</p> css beginners webdev programming Some amazing JS components Adebayo Olamilekan Sun, 04 Dec 2022 09:00:11 +0000 https://dev.to/oleanji/some-amazing-js-components-50fk https://dev.to/oleanji/some-amazing-js-components-50fk <p>We all want to make this cool website with all these amazing features, well I'll help with some of those features like;</p> <ol> <li><p><a href="proxy.php?url=https://www.npmjs.com/package/react-scroll" rel="noopener noreferrer">React-scroll</a>: This react component that helps to animate vertical scrolling on your webpage/web app. Cool rightπŸ€— ?</p></li> <li><p><a href="proxy.php?url=https://www.npmjs.com/package/react-intersection-observer" rel="noopener noreferrer">React intersection observer</a>: This is another amazing js component that you can implement in your web project to do anything like animation, text/ background color change, etc. The react intersection observer tells you when an element enters a certain viewport.</p></li> </ol> <p><em>Why all this explanation with no example πŸ™„</em>, Don't worry I got you covered ;).</p> <p>This is an example of using the above react components in your web project.</p> <p><a href="proxy.php?url=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%2Fajbpydnizyt3zillsb57.gif" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fajbpydnizyt3zillsb57.gif" alt="Result" width="600" height="338"></a></p> <p>The link to check out the above demonstration is <a href="proxy.php?url=https://react-scroll-tuts.vercel.app/" rel="noopener noreferrer">here</a> or check out my git repo <a href="proxy.php?url=https://github.com/OleanjiKingCode/react-scroll-tuts" rel="noopener noreferrer">here</a></p> <p><strong><em>Let get buildy</em> πŸ‘·πŸ»β€β™‚οΈπŸ› οΈ</strong></p> <p><strong>Technologies Used</strong></p> <ul> <li><a href="proxy.php?url=https://nextjs.org/docs" rel="noopener noreferrer">Next Js</a></li> <li><a href="proxy.php?url=https://tailwindcss.com/docs/guides/nextjs" rel="noopener noreferrer">Tailwind CSS</a></li> <li><a href="proxy.php?url=https://www.npmjs.com/package/react-scroll" rel="noopener noreferrer">React-scroll</a></li> <li><a href="proxy.php?url=https://react-intersection-observer.vercel.app/" rel="noopener noreferrer">React-intersection-observer</a></li> </ul> <p>After a successful Installation of the above technologies, the folders in code editor should be similar to:</p> <p><a href="proxy.php?url=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%2Fyj9ix4j0uwxk3p69b4mc.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fyj9ix4j0uwxk3p69b4mc.png" alt="Code editor" width="316" height="560"></a></p> <h2> Step 1 </h2> <p>Go to your <em>Index.js</em> file inside the pages folder and<br> import theses necessary components to be used in the example<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight javascript"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">Link</span><span class="p">,</span> <span class="nx">Element</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react-scroll</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">useInView</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react-intersection-observer</span><span class="dl">"</span><span class="p">;</span> </code></pre> </div> <p>The Link class imported from the react-scroll component serves as a link to the Element class also imported.<br> Which means the <em>Link_scrolls to the specified _Element</em>.</p> <p>Whereby the useInView hook checks if a particular element is in view when scrolling action a]happens on the screen.</p> <h2> Step 2 </h2> <p>Copy this into the <em>Home default function</em><br> </p> <div class="highlight js-code-highlight"> <pre class="highlight javascript"><code><span class="c1">// These are references to each page shown </span> <span class="kd">const</span> <span class="p">{</span> <span class="na">ref</span><span class="p">:</span> <span class="nx">PAGE_ONE</span><span class="p">,</span> <span class="na">inView</span><span class="p">:</span> <span class="nx">viewOne</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">useInView</span><span class="p">({</span> <span class="na">threshold</span><span class="p">:</span> <span class="mf">0.3</span><span class="p">,</span> <span class="p">});</span> <span class="kd">const</span> <span class="p">{</span> <span class="na">ref</span><span class="p">:</span> <span class="nx">PAGE_TWO</span><span class="p">,</span> <span class="na">inView</span><span class="p">:</span> <span class="nx">viewTwo</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">useInView</span><span class="p">({</span> <span class="na">threshold</span><span class="p">:</span> <span class="mf">0.3</span><span class="p">,</span> <span class="p">});</span> <span class="kd">const</span> <span class="p">{</span> <span class="na">ref</span><span class="p">:</span> <span class="nx">PAGE_THREE</span><span class="p">,</span> <span class="na">inView</span><span class="p">:</span> <span class="nx">viewThree</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">useInView</span><span class="p">({</span> <span class="na">threshold</span><span class="p">:</span> <span class="mf">0.3</span><span class="p">,</span> <span class="p">});</span> <span class="kd">const</span> <span class="p">{</span> <span class="na">ref</span><span class="p">:</span> <span class="nx">PAGE_FOUR</span><span class="p">,</span> <span class="na">inView</span><span class="p">:</span> <span class="nx">viewFour</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">useInView</span><span class="p">({</span> <span class="na">threshold</span><span class="p">:</span> <span class="mf">0.3</span><span class="p">,</span> <span class="p">});</span> <span class="c1">// An array of each page and its details</span> <span class="kd">const</span> <span class="nx">pagesAndDetails</span> <span class="o">=</span> <span class="p">[</span> <span class="p">{</span> <span class="na">title</span><span class="p">:</span> <span class="dl">"</span><span class="s2">PAGE_ONE</span><span class="dl">"</span><span class="p">,</span> <span class="na">details</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Details of Page One</span><span class="dl">"</span> <span class="p">},</span> <span class="p">{</span> <span class="na">title</span><span class="p">:</span> <span class="dl">"</span><span class="s2">PAGE_TWO</span><span class="dl">"</span><span class="p">,</span> <span class="na">details</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Details of Page Two</span><span class="dl">"</span> <span class="p">},</span> <span class="p">{</span> <span class="na">title</span><span class="p">:</span> <span class="dl">"</span><span class="s2">PAGE_THREE</span><span class="dl">"</span><span class="p">,</span> <span class="na">details</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Details of Page Three</span><span class="dl">"</span> <span class="p">},</span> <span class="p">{</span> <span class="na">title</span><span class="p">:</span> <span class="dl">"</span><span class="s2">PAGE_FOUR</span><span class="dl">"</span><span class="p">,</span> <span class="na">details</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Details of Page Four</span><span class="dl">"</span> <span class="p">},</span> <span class="p">];</span> <span class="c1">// An array of each page's colors</span> <span class="kd">const</span> <span class="nx">colors</span> <span class="o">=</span> <span class="p">[</span><span class="dl">"</span><span class="s2">#b8c7ce </span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">#E9E948</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">#f1f1f1 </span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">#7bc191</span><span class="dl">"</span><span class="p">];</span> </code></pre> </div> <h2> Step 3 </h2> <p>Copt this into the return function<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight javascript"><code><span class="o">&lt;&gt;</span> <span class="o">&lt;</span><span class="nx">Head</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">title</span><span class="o">&gt;</span><span class="nx">React</span> <span class="nx">Scroll</span> <span class="nx">Web</span><span class="o">&lt;</span><span class="sr">/title</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">meta</span> <span class="nx">name</span><span class="o">=</span><span class="dl">"</span><span class="s2">description</span><span class="dl">"</span> <span class="nx">content</span><span class="o">=</span><span class="dl">"</span><span class="s2">An example of a react scroll website</span><span class="dl">"</span> <span class="o">/&gt;</span> <span class="o">&lt;</span><span class="nx">link</span> <span class="nx">rel</span><span class="o">=</span><span class="dl">"</span><span class="s2">icon</span><span class="dl">"</span> <span class="nx">href</span><span class="o">=</span><span class="dl">"</span><span class="s2">/favicon.ico</span><span class="dl">"</span> <span class="o">/&gt;</span> <span class="o">&lt;</span><span class="sr">/Head</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">w-full</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">flex flex-wrap items-center justify-between px-12 fixed</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Link</span> <span class="nx">activeClass</span><span class="o">=</span><span class="dl">"</span><span class="s2">active</span><span class="dl">"</span> <span class="nx">to</span><span class="o">=</span><span class="dl">"</span><span class="s2">PAGE ONE</span><span class="dl">"</span> <span class="nx">spy</span> <span class="nx">smooth</span> <span class="nx">duration</span><span class="o">=</span><span class="p">{</span><span class="mi">700</span><span class="p">}</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">px-3 py-3 mb-2 bg-[#b8c7ce] rounded-xl border-2 border-white cursor-pointer mr-4</span><span class="dl">"</span> <span class="o">&gt;</span> <span class="p">{</span><span class="nx">viewOne</span> <span class="p">?</span> <span class="p">(</span> <span class="o">&lt;</span><span class="nx">span</span><span class="o">&gt;</span><span class="nx">YOU</span> <span class="nx">ARE</span> <span class="nx">AT</span> <span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">title</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/span</span><span class="err">&gt; </span> <span class="p">)</span> <span class="p">:</span> <span class="p">(</span> <span class="o">&lt;</span><span class="nx">span</span><span class="o">&gt;</span> <span class="nx">GO</span> <span class="nx">TO</span> <span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">title</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/span</span><span class="err">&gt; </span> <span class="p">)}</span> <span class="o">&lt;</span><span class="sr">/Link</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">Link</span> <span class="nx">activeClass</span><span class="o">=</span><span class="dl">"</span><span class="s2">active</span><span class="dl">"</span> <span class="nx">to</span><span class="o">=</span><span class="dl">"</span><span class="s2">PAGE TWO</span><span class="dl">"</span> <span class="nx">spy</span> <span class="nx">smooth</span> <span class="nx">duration</span><span class="o">=</span><span class="p">{</span><span class="mi">700</span><span class="p">}</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">px-3 py-3 mb-2 bg-[#E9E948] rounded-xl border-2 border-white cursor-pointer mr-4</span><span class="dl">"</span> <span class="o">&gt;</span> <span class="p">{</span><span class="nx">viewTwo</span> <span class="p">?</span> <span class="p">(</span> <span class="o">&lt;</span><span class="nx">span</span><span class="o">&gt;</span><span class="nx">YOU</span> <span class="nx">ARE</span> <span class="nx">AT</span> <span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">title</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/span</span><span class="err">&gt; </span> <span class="p">)</span> <span class="p">:</span> <span class="p">(</span> <span class="o">&lt;</span><span class="nx">span</span><span class="o">&gt;</span> <span class="nx">GO</span> <span class="nx">TO</span> <span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">title</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/span</span><span class="err">&gt; </span> <span class="p">)}</span> <span class="o">&lt;</span><span class="sr">/Link</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">Link</span> <span class="nx">activeClass</span><span class="o">=</span><span class="dl">"</span><span class="s2">active</span><span class="dl">"</span> <span class="nx">to</span><span class="o">=</span><span class="dl">"</span><span class="s2">PAGE THREE</span><span class="dl">"</span> <span class="nx">spy</span> <span class="nx">smooth</span> <span class="nx">duration</span><span class="o">=</span><span class="p">{</span><span class="mi">700</span><span class="p">}</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">px-3 py-3 mb-2 bg-[#f1f1f1] rounded-xl border-2 border-white cursor-pointer mr-4</span><span class="dl">"</span> <span class="o">&gt;</span> <span class="p">{</span><span class="nx">viewThree</span> <span class="p">?</span> <span class="p">(</span> <span class="o">&lt;</span><span class="nx">span</span><span class="o">&gt;</span><span class="nx">YOU</span> <span class="nx">ARE</span> <span class="nx">AT</span> <span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="nx">title</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/span</span><span class="err">&gt; </span> <span class="p">)</span> <span class="p">:</span> <span class="p">(</span> <span class="o">&lt;</span><span class="nx">span</span><span class="o">&gt;</span> <span class="nx">GO</span> <span class="nx">TO</span> <span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="nx">title</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/span</span><span class="err">&gt; </span> <span class="p">)}</span> <span class="o">&lt;</span><span class="sr">/Link</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">Link</span> <span class="nx">activeClass</span><span class="o">=</span><span class="dl">"</span><span class="s2">active</span><span class="dl">"</span> <span class="nx">to</span><span class="o">=</span><span class="dl">"</span><span class="s2">PAGE FOUR</span><span class="dl">"</span> <span class="nx">spy</span> <span class="nx">smooth</span> <span class="nx">duration</span><span class="o">=</span><span class="p">{</span><span class="mi">700</span><span class="p">}</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">px-3 py-3 mb-2 bg-[#7bc191] rounded-xl border-2 border-white cursor-pointer mr-4</span><span class="dl">"</span> <span class="o">&gt;</span> <span class="p">{</span><span class="nx">viewFour</span> <span class="p">?</span> <span class="p">(</span> <span class="o">&lt;</span><span class="nx">span</span><span class="o">&gt;</span><span class="nx">YOU</span> <span class="nx">ARE</span> <span class="nx">AT</span> <span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="nx">title</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/span</span><span class="err">&gt; </span> <span class="p">)</span> <span class="p">:</span> <span class="p">(</span> <span class="o">&lt;</span><span class="nx">span</span><span class="o">&gt;</span> <span class="nx">GO</span> <span class="nx">TO</span> <span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="nx">title</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/span</span><span class="err">&gt; </span> <span class="p">)}</span> <span class="o">&lt;</span><span class="sr">/Link</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">Element</span> <span class="nx">name</span><span class="o">=</span><span class="dl">"</span><span class="s2">PAGE ONE</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="s2">`w-full h-screen py-3`</span><span class="p">}</span> <span class="nx">style</span><span class="o">=</span><span class="p">{{</span> <span class="na">backgroundColor</span><span class="p">:</span> <span class="nx">colors</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="p">}}</span> <span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">ref</span><span class="o">=</span><span class="p">{</span><span class="nx">PAGE_ONE</span><span class="p">}</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="s2">`w-full h-full -mt-16 flex flex-col items-center text-center justify-center `</span><span class="p">}</span> <span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="s2">`w-full mt-2 py-5 font-bold text-2xl `</span><span class="p">}</span><span class="o">&gt;</span> <span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">title</span><span class="p">}</span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">w-full text-sm</span><span class="dl">"</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">details</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Element</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">Element</span> <span class="nx">name</span><span class="o">=</span><span class="dl">"</span><span class="s2">PAGE TWO</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="s2">`w-full h-screen py-3`</span><span class="p">}</span> <span class="nx">style</span><span class="o">=</span><span class="p">{{</span> <span class="na">backgroundColor</span><span class="p">:</span> <span class="nx">colors</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="p">}}</span> <span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">ref</span><span class="o">=</span><span class="p">{</span><span class="nx">PAGE_TWO</span><span class="p">}</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="s2">`w-full h-full -mt-16 flex flex-col items-center text-center justify-center `</span><span class="p">}</span> <span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="s2">`w-full mt-2 py-5 font-bold text-2xl `</span><span class="p">}</span><span class="o">&gt;</span> <span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">title</span><span class="p">}</span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">w-full text-sm</span><span class="dl">"</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">details</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Element</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">Element</span> <span class="nx">name</span><span class="o">=</span><span class="dl">"</span><span class="s2">PAGE THREE</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="s2">`w-full h-screen py-3`</span><span class="p">}</span> <span class="nx">style</span><span class="o">=</span><span class="p">{{</span> <span class="na">backgroundColor</span><span class="p">:</span> <span class="nx">colors</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="p">}}</span> <span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">ref</span><span class="o">=</span><span class="p">{</span><span class="nx">PAGE_THREE</span><span class="p">}</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="s2">`w-full h-full -mt-16 flex flex-col items-center text-center justify-center `</span><span class="p">}</span> <span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="s2">`w-full mt-2 py-5 font-bold text-2xl `</span><span class="p">}</span><span class="o">&gt;</span> <span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="nx">title</span><span class="p">}</span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">w-full text-sm</span><span class="dl">"</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="nx">details</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Element</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">Element</span> <span class="nx">name</span><span class="o">=</span><span class="dl">"</span><span class="s2">PAGE FOUR</span><span class="dl">"</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="s2">`w-full h-screen py-3`</span><span class="p">}</span> <span class="nx">style</span><span class="o">=</span><span class="p">{{</span> <span class="na">backgroundColor</span><span class="p">:</span> <span class="nx">colors</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="p">}}</span> <span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">ref</span><span class="o">=</span><span class="p">{</span><span class="nx">PAGE_FOUR</span><span class="p">}</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="s2">`w-full h-full -mt-16 flex flex-col items-center text-center justify-center `</span><span class="p">}</span> <span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="s2">`w-full mt-2 py-5 font-bold text-2xl `</span><span class="p">}</span><span class="o">&gt;</span> <span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="nx">title</span><span class="p">}</span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">w-full text-sm</span><span class="dl">"</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">pagesAndDetails</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="nx">details</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/Element</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/</span><span class="err">&gt; </span></code></pre> </div> <p>The above code links each button to a page element and changes text when the page is in view.</p> <h2> Step 4 </h2> <p>Run the project<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight javascript"><code><span class="nx">npm</span> <span class="nx">run</span> <span class="nx">dev</span> <span class="c1">// or</span> <span class="nx">yarn</span> <span class="nx">dev</span> </code></pre> </div> <p><strong>Great work</strong> πŸŽŠπŸŽŠπŸŽ‰πŸŽ‰</p> <p>There are more better ways to use these components in your project this is just a simple example.</p> <p>Look out for more amazing JS components.</p> react webdev javascript beginners Installing foundry toolchain on windows. Adebayo Olamilekan Wed, 02 Nov 2022 20:08:39 +0000 https://dev.to/oleanji/installing-foundry-toolchain-on-windows-27ml https://dev.to/oleanji/installing-foundry-toolchain-on-windows-27ml <p>As windows users, we mostly suffer when installing complicated software and programs on our machines, just like <a href="proxy.php?url=https://book.getfoundry.sh/" rel="noopener noreferrer">foundry</a> smart contract tool-chain.</p> <p>Foundry manages your dependencies, compiles your project, runs tests, deploys, and lets you interact with the chain from the command line and via Solidity scripts. <em>(from official website)</em></p> <p>Using Foundry to compile, test and deploy is much faster and better compared to other smart contract tools like <a href="proxy.php?url=https://hardhat.org/" rel="noopener noreferrer">hardhat</a> or truffle because using foundry is not only faster but testing and deployments are all written in solidity and not JavaScript.</p> <p>Foundry doesn't only use solidity for testing and deployment, it also has the following interesting tools:</p> <p>1) <strong>Forge</strong>:This is a command-line tool of foundry, that is used to install dependencies, build contracts, test them, deploy and also verify smart contracts.<br> 2) <strong>Cast</strong>:This helps with smart contracts calls both locally and onchain (awesome right).<br> 3) <strong>Anvil</strong>:This is the last tool of foundry and this serves as a local testnet, just like hardhat local node and ganache.</p> <p>A Little more details on this on this Twitter <a href="proxy.php?url=https://twitter.com/Oleanji_sol/status/1579772754517102592?s=20&amp;t=1sanVDzwrVIACuYxwuxUUw" rel="noopener noreferrer">thread</a></p> <p>So to use Foundry on our machines we follow the steps given on their <a href="proxy.php?url=https://book.getfoundry.sh/" rel="noopener noreferrer">site</a> </p> <p><a href="proxy.php?url=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%2F02tkjkner02rxseqlbar.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F02tkjkner02rxseqlbar.png" alt="Linux and MacOs" width="800" height="449"></a><br> A couple of commands are just needed to get foundry ready on both mac and Linux machines but not windows.</p> <p><a href="proxy.php?url=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%2Flnnzrglt5nphq8nx0fr2.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Flnnzrglt5nphq8nx0fr2.png" alt="Windows" width="800" height="510"></a></p> <h2> *<em>Steps to get Foundry on your Windows PC *</em> </h2> <p>1) Download rust by going to <a href="proxy.php?url=https://rustup.rs/" rel="noopener noreferrer">rust</a>. <br> <a href="proxy.php?url=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%2Fv0lzezpg0gb3djpsharg.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fv0lzezpg0gb3djpsharg.png" alt="rust" width="800" height="382"></a><br> 2) After successful installation, run the installed exe file, which should open up a window like command prompt.</p> <ul> <li>if the window shows up like this then "Proceed with installation" by either pressing the "Enter" key or 1 and then press the "Enter" key.</li> </ul> <p><a href="proxy.php?url=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%2Fdaw88z2f5n919wsztynx.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fdaw88z2f5n919wsztynx.png" alt="Ready to install forge" width="800" height="415"></a></p> <ul> <li>But in case it doesn't look like the above and like this picture (below) </li> </ul> <p><a href="proxy.php?url=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%2Fl0m439tin2rozhj1fgbi.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fl0m439tin2rozhj1fgbi.png" alt="No packages yet" width="800" height="404"></a></p> <ul> <li>Then you'll have to download Microsoft Visual Studio <a href="proxy.php?url=https://visualstudio.microsoft.com/downloads/" rel="noopener noreferrer">here</a> </li> </ul> <p><a href="proxy.php?url=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%2Fsrgtx655qhvpmzj66jh5.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fsrgtx655qhvpmzj66jh5.png" alt="Download" width="800" height="341"></a></p> <ul> <li>Then install the following packages, i.e tick the boxes ticked here (below) just like what was required in the rust exe window. _ [Packages to install: MSVC &amp; Windows 10 SDK]_</li> </ul> <p><a href="proxy.php?url=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%2Fi9g615veyhtbelafhk1b.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fi9g615veyhtbelafhk1b.png" alt="Packages" width="320" height="303"></a></p> <p>Installation process</p> <p><a href="proxy.php?url=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%2Ffeuijfzn0ap3z70jxi61.PNG" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Ffeuijfzn0ap3z70jxi61.PNG" alt="installation" width="800" height="454"></a></p> <ul> <li>After a successful downloading and installation then re-run the rust exe and it should look like this </li> </ul> <p><a href="proxy.php?url=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%2Fh3wo3yerh3o8hfhvle6a.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fh3wo3yerh3o8hfhvle6a.png" alt="Now" width="800" height="415"></a><br> So you can now proceed with the installation.</p> <p>The installation of foundry (forge, cast, and anvil) might take a while, But after it's done you can check if it's installed by running this command:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>forge -V </code></pre> </div> <p>or<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>forge --version </code></pre> </div> <p>Now you can use foundry in building smart contracts :)</p> foundry smartcontract web3 windows 6 Chrome extensionπŸ”§ βš™that can boost your productivity as a web developer πŸ‘©β€πŸ’» πŸš€πŸš€ Adebayo Olamilekan Wed, 07 Sep 2022 17:03:16 +0000 https://dev.to/oleanji/6-chrome-extension-that-can-boost-your-productivity-as-a-web-developer-35pg https://dev.to/oleanji/6-chrome-extension-that-can-boost-your-productivity-as-a-web-developer-35pg <p>As a beginner or intermediate web developer most times we wish there are somethings we can debug and locate errors for before checking back to our super lengthy code 😩.</p> <p>Good news thoughπŸ‘πŸ½, I got you covered ;). There are extensions/tools that can be installed and used on the chrome browser to boost our productivity as a developer</p> <p>Here are six (6) chrome extensions that can boost your productivity :</p> <ol> <li> <a href="proxy.php?url=https://chrome.google.com/webstore/detail/pesticide-for-chrome/bakpbgckdnepkmkeaiomhmfcnejndkbi" rel="noopener noreferrer">Pesticide</a> </li> <li><a href="proxy.php?url=https://chrome.google.com/webstore/detail/eye-dropper/hmdcmlfkchdmnmnmheododdhjedfccka" rel="noopener noreferrer">Eye Dropper</a></li> <li><a href="proxy.php?url=https://chrome.google.com/webstore/detail/page-ruler/jcbmcnpepaddcedmjdcmhbekjhbfnlff" rel="noopener noreferrer">Page Ruler</a></li> <li> <a href="proxy.php?url=https://chrome.google.com/webstore/detail/font-finder/pkiokiaeahklmefmfpnnofmgfafajpdl" rel="noopener noreferrer">Font Finder</a> </li> <li><a href="proxy.php?url=https://chrome.google.com/webstore/detail/gofullpage-full-page-scre/fdpohaocaechififmbbbbbknoalclacl" rel="noopener noreferrer">GoFullPage</a></li> <li> <a href="proxy.php?url=https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh" rel="noopener noreferrer">JSON viewer</a> </li> </ol> <p><strong>Pesticide</strong></p> <p>As web developers we sometimes run into situations where the result of our styling isn't what we expected and this can be so frustrating 😫.</p> <p>Well pesticide helps with this.<br> It outlines each element and see how your elements are nested in one another and this is really awesome.</p> <p>There are two types of pesticide chrome extension, one is with hover bar while the other isn't.</p> <p><a href="proxy.php?url=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%2Fekknddv2t0zdc8xlvwsk.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fekknddv2t0zdc8xlvwsk.png" alt="Pesticide on Canva" width="800" height="397"></a></p> <p>The above picture shows the use of pesticide on <a href="proxy.php?url=//canva.com">Canva</a></p> <p>Pesticide can be gotten from <a href="proxy.php?url=https://chrome.google.com/webstore/detail/pesticide-for-chrome/bakpbgckdnepkmkeaiomhmfcnejndkbi" rel="noopener noreferrer">here</a></p> <p><strong>Eye Dropper</strong></p> <p>Most developers are not really friends with our UI designers πŸ˜‚, this is because of the breath-taking designs and colors we are to code. </p> <p>Getting the right colors can sometimes be a headache,. especially when you wanna clone an app or website and you can seem to get the specific colors, in that case you can use the eye dropper chrome extension.</p> <p>The eye dropper chrome extension helps you to get colors from Web pages and this is do damn useful.</p> <p>You can just visit the figma page of the <br> UI design, use the eye dropper extension and get the colors used.</p> <p><a href="proxy.php?url=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%2Fm9a5zlg7pmpgx2dmn6sh.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fm9a5zlg7pmpgx2dmn6sh.png" alt="Eye dropper" width="565" height="304"></a></p> <p>Eye dropper can be gotten from <a href="proxy.php?url=https://chrome.google.com/webstore/detail/eye-dropper/hmdcmlfkchdmnmnmheododdhjedfccka" rel="noopener noreferrer">here</a></p> <p><strong>Page Ruler</strong></p> <p>Getting the exact dimensions (width, height) of an object in your Web page can be helpful.</p> <p>Either when duplicating a website and you need the exact dimensions of an object on a webpage or for any other project you're working on that you need the exact dimensions from a Web page. Then the <strong>page ruler</strong> is here to rescue you πŸ“πŸ‘©β€βš•οΈ.</p> <p>It's when activated this extension goes in a <em>Ruler mode</em> and when you drag your mouse, it create a box and it gives full details of the dimensions.</p> <p><a href="proxy.php?url=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%2Fd240lxv62uexa1esw8u8.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fd240lxv62uexa1esw8u8.png" alt="Page Ruler" width="800" height="391"></a></p> <p>The above image shows the ruler chrome extension used on my github page and it can be gotten from <a href="proxy.php?url=https://chrome.google.com/webstore/detail/page-ruler/jcbmcnpepaddcedmjdcmhbekjhbfnlff" rel="noopener noreferrer">here</a></p> <p><strong>GoFullPage Chrome extension</strong></p> <p>Are you a beginner in web dev?</p> <p>If so, you may have wondered how others get a full picture of webpages they build and you also want to do this either to see the full result of your hardwork or send it to a client<br> Gofullpage is the secret solution πŸ€—</p> <p>This chrome extension helps you to get the full image of your webpage, and gives you options to either get it in pdf or in jpg.</p> <p>It also have an editor that you can use to edit your new Web page image.</p> <p><a href="proxy.php?url=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%2F0o0ew066h8ntsi5kckuy.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F0o0ew066h8ntsi5kckuy.png" alt="In progress" width="339" height="167"></a></p> <p><a href="proxy.php?url=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%2Fa95eione2vk3dt7xb8w0.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fa95eione2vk3dt7xb8w0.png" alt="Full page screen cap" width="800" height="391"></a></p> <p>The link is <a href="proxy.php?url=https://chrome.google.com/webstore/detail/gofullpage-full-page-scre/fdpohaocaechififmbbbbbknoalclacl" rel="noopener noreferrer">here</a></p> <p><strong>Font Finder</strong> </p> <p>This is an all-in-one tool as the name implies this chrome extension Is used to get details of a font used on a webpage, but it does so much more than that like the details of the font selected, the color, line height, font weight etc.</p> <p>When using this tool, and then you hover on your webpage this extension gives details on the element and it type then a full description when you click on it.</p> <p><a href="proxy.php?url=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%2Fum7pfhrh3euf2k9uun0t.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fum7pfhrh3euf2k9uun0t.png" alt="Using on my git page" width="800" height="399"></a></p> <p>Get it <a href="proxy.php?url=https://chrome.google.com/webstore/detail/font-finder/pkiokiaeahklmefmfpnnofmgfafajpdl" rel="noopener noreferrer">here</a></p> <p>*<em>JSON viewer *</em></p> <p>Dealing with json data format can be confusing at times πŸ˜•. The format may not be structured well and you don't understand it that way..</p> <p>Json viewer helps to structure your json data on your webpage.</p> <p>It automatically structures it and even had code lines.</p> <p>Get it <a href="proxy.php?url=https://t.co/9k2Px5DkMe" rel="noopener noreferrer">here</a></p> <p>This is the end of this article, I hope you found these extensions useful and if you already use some I hope you found some more here.</p> <p><strong>NOTE</strong> : There are over 130,000 extensions on chrome and this is just so small, so you can explore more at the <a href="proxy.php?url=https://chrome.google.com/webstore/category/extensions" rel="noopener noreferrer">store</a></p> webdev tooling programming beginners How to Create a FullStack Dapp using Next JS, Tailwind CSS and The graph. (Part 2) Adebayo Olamilekan Thu, 01 Sep 2022 11:37:16 +0000 https://dev.to/oleanji/how-to-create-a-fullstack-dapp-using-next-js-tailwind-css-and-the-graph-part-2-lob https://dev.to/oleanji/how-to-create-a-fullstack-dapp-using-next-js-tailwind-css-and-the-graph-part-2-lob <p>Hi there, welcome to the second part of a two-series tutorial on how to create a Fullstack dapp using web3 technologies some of which are:</p> <ul> <li>Tailwind Css <em>for styling</em> </li> <li>The graph <em>for indexing data</em> </li> <li>Next Js <em>react framework to build our application</em> </li> <li>Solidity <em>for writing smart contracts</em> </li> <li>Web3 . strorage <em>for storing our data</em> </li> <li>Ethers . js <em>Library for interacting with the blockchain</em> </li> </ul> <p>If you have gone through the first part of this series and want to understand this much better you can get it at <a href="proxy.php?url=https://dev.to/oleanji/how-to-create-a-fullstack-dapp-using-next-js-tailwind-css-and-the-graph-part-1-2e77">Part One of NFT AIR Tutorial</a></p> <p>Its been a few weeks since I wrote the first part of this tutorial and I'm sorry about that πŸ™, but before starting this part (Frontend aspect) we need to know what <strong>we've done</strong> and ** what is to be done**;</p> <p>NFT AIR Dapp Project</p> <ol> <li>Create a nextJs application βœ…</li> <li> Install the necessary dependencies βœ…</li> <li> Write our smart contract βœ…</li> <li> Test the contract βœ…</li> <li> Deploy the Contract βœ…</li> <li> Create and connect your Project with your subgraph βœ…</li> <li> Install more dependencies </li> <li> Getting assets (Pictures) used in the project</li> <li> Creating Pages, Components and writing Queries (i.e wallet connection, contract interaction, data retrieval from the graph ectera)</li> <li>Testing and Running.</li> <li>Create and Upload an art.</li> </ol> <p>So far we are done with 6 out of 11 things to do to create our fullstack dapp project, and that's progress πŸ€—πŸ’–.<br> It only remains 5 things to do to get our full project ready,<br> this πŸ‘‡</p> <p><a href="proxy.php?url=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%2Fyshrm4vsnqlald90arzp.gif" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fyshrm4vsnqlald90arzp.gif" alt="Preview of Full dapp" width="1200" height="589"></a></p> <h2> Prerequisites </h2> <p>Like in the previous tutorial you should ensure that you have the following on your machine.</p> <ol> <li>Text Editor of your choice Installed on your machine (preferably <a href="proxy.php?url=https://code.visualstudio.com/" rel="noopener noreferrer">Vs code</a> )</li> <li>Have <a href="proxy.php?url=https://nodejs.org/en/" rel="noopener noreferrer">npm</a> or <a href="proxy.php?url=https://classic.yarnpkg.com/lang/en/docs/install/#windows-stable" rel="noopener noreferrer">yarn</a> installed </li> <li>[Most Important] Have a glass of juice, coffee or bag of chips beside you, because this can get tiring and you should be able to snack and get your energy back ;) </li> </ol> <h2> Project BuidLing and Setup </h2> <p>Lets Begin! (Take a sip of that drink or a bite from that snack and lets get buidl-y πŸ˜… )</p> <ol> <li>Installing more dependencies We've installed quite a few dependencies in the last tutorial, but those pertain to the backend of the Dapp and now we will be installing more dependencies for the frontend aspect of this application. we'll be installing:</li> </ol> <ul> <li>Tailwind Css (Styling)</li> <li>web3 storage (Storing and retrieiving data)</li> <li>rainbow kit (wallet connection)</li> <li>wagmi (React hook for wallet connection)</li> <li> <p>axios </p> <ul> <li>Installing rainbow kit for wallet connection, wagmi a collection of react hooks for dealing with wallet connection, ethers for blockchain interaction from the frontend (If you already have it installed you can choose to remove it), </li> </ul> </li> </ul> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>yarn add @rainbow-me/rainbowkit wagmi ethers axios urql graphql react-icons </code></pre> </div> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> - To use Web3 storage in our project we do not only need to install it dependency but also create an account [here] (https://web3.storage/) and then also create a token, this token is what will be used to upload files to web3 storage. Read more about the [docs] (https://web3.storage/docs/how-tos/generate-api-token/), and urql is used to fetch data from a subgraph. </code></pre> </div> <p>To install web3 Storage<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>npm install web3.storage yarn add web3.storage </code></pre> </div> <p><strong>Getting your token</strong><br> <a href="proxy.php?url=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%2Faise43y5mof7dfxnz2ci.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Faise43y5mof7dfxnz2ci.png" alt="Token creation webStorage" width="800" height="301"></a></p> <p>After getting your token, you can add it to your constant.js file like this;<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>export const Token = "YOUR_TOKEN_HERE" </code></pre> </div> <p>We also need our graph api that we'll be using to query data from our subgraph, and this is gotten from our subgraph page.</p> <p>Go to <a href="proxy.php?url=https://thegraph.com/hosted-service" rel="noopener noreferrer">the graph hosted service</a> and go to <em>My Dashboard</em>, open up your NFT AIR Subgraph and get your api key from there.</p> <p><a href="proxy.php?url=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%2Fpih1f74309pctq6f4e0i.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fpih1f74309pctq6f4e0i.png" alt="Api key" width="710" height="491"></a></p> <p>The Api key is below the <em>QUERIES (HTTP)</em> heading copy that and put it in your constants file.</p> <p>Now your constants file should have 3 constants; </p> <ol> <li>NFT AIR address </li> <li>Token from web3 storage.</li> <li>Api key from your subgragh</li> </ol> <p>-To install Tailwind css<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p </code></pre> </div> <p>After installation you should follow the steps on how to continue <a href="proxy.php?url=https://tailwindcss.com/docs/guides/nextjs" rel="noopener noreferrer">here</a> in their docs.</p> <h2> Getting Assets for the Dapp </h2> <p>I used some pngs in my dapp and to get that you can go to public folder in my <a href="proxy.php?url=https://github.com/OleanjiKingCode/Improved-MemeForest/tree/master/public" rel="noopener noreferrer">repo</a> and download them.</p> <h2> Creating pages, components and writing queries </h2> <p>Here we start showing UI for the code we have written so far, in form of pages on the website just like the preview below</p> <p><a href="proxy.php?url=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%2F1e6sjs7uumrcyknczgrv.gif" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F1e6sjs7uumrcyknczgrv.gif" alt="Preview" width="1200" height="589"></a></p> <p>We will be creating this pages:</p> <ol> <li>Register/Dashboard (Homepage)</li> <li>Feed (Shows list of all art uploaded)</li> <li>Starred page (shows starred art of a user)</li> <li>Creations page (Shows all your creation)</li> <li>Create page ( This is where we create the art and upload them)</li> <li>Components: <ul> <li>Loader component</li> <li>Navbar component</li> </ul> </li> </ol> <p>We would start with the building of the components first;</p> <ul> <li>*<em>The Loader component *</em> This shows up when a new page is to loaded, or a current one reloaded. The code is short so you can decide not to make it a component and decide to implement it in every page.</li> </ul> <p>First create a new folder in your root directory with <em>components</em> as its name, and a new file named loader.js with this code in it .<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>const Loader = () =&gt; { return ( &lt;div className="flex items-center justify-center h-screen bg-white "&gt; &lt;img src="proxy.php?url=/loading.png" alt="loading..." /&gt; &lt;/div&gt; ) } export default Loader </code></pre> </div> <ul> <li>Navbar Component </li> </ul> <p>This contains the various pages for our dapp and its responsive for both pc and mobile view<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>import Link from "next/link" import {useState } from "react"; import { HiMenu } from "react-icons/hi"; import { BiX } from "react-icons/bi"; function Navbar () { const [openMenu,setOpenMenu] = useState(false) return ( &lt;nav className='shadow-md fixed w-full z-50 '&gt; &lt;div className='flex items-center bg-white h-24 rounded-b-lg w-full' &gt; &lt;div className='flex items items-center w-full mx-5 md:mx-20 justify-between'&gt; &lt;div className='flex items-center justify-center '&gt; &lt;h1 className='font-bold text-2xl cursor-pointer'&gt; NFT &lt;span className='text-green-400'&gt; AIR&lt;/span&gt; &lt;/h1&gt; &lt;/div&gt; &lt;div className='hidden md:block'&gt; &lt;div className='ml-10 flex items-baseline space-x-8'&gt; &lt;Link href="proxy.php?url=/" className=' cusor-pointer '&gt; &lt;div className='no-underline font-semibold text-black-600 hover:text-orange-600 cursor-pointer'&gt; Home &lt;/div&gt; &lt;/Link&gt; &lt;Link href="proxy.php?url=/Feed" className=' cusor-pointer '&gt; &lt;div className='no-underline font-semibold text-black-600 hover:text-orange-600 cursor-pointer'&gt; Feed &lt;/div&gt; &lt;/Link&gt; &lt;Link href="proxy.php?url=/starred" className=' cusor-pointer '&gt; &lt;div className='no-underline font-semibold text-black-600 hover:text-orange-600 cursor-pointer'&gt; Starred &lt;/div&gt; &lt;/Link&gt; &lt;Link href="proxy.php?url=/creations" className=' cusor-pointer '&gt; &lt;div className='no-underline font-semibold text-black-600 hover:text-orange-600 cursor-pointer'&gt; Creations &lt;/div&gt; &lt;/Link&gt; &lt;Link href="proxy.php?url=/create" className=' cusor-pointer '&gt; &lt;button className='no-underline bg-green-500 py-2 px-3 rounded-lg font-bold text-teal-50 hover:bg-orange-500 cursor-pointer '&gt; Create NFT &lt;/button&gt; &lt;/Link&gt; &lt;/div&gt; &lt;/div&gt; &lt;div className='block md:hidden'&gt; &lt;button onClick={()=&gt; setOpenMenu(!openMenu)} className=' ml-10 cursor-pointer flex items-center bg-green-500 text-gray-50 hover:bg-orange-500 px-2 py-2 rounded-lg '&gt; { !openMenu ? ( &lt;HiMenu className='font-bold text-2xl' /&gt; ) : ( &lt;BiX className='font-bold text-2xl' /&gt; ) } &lt;/button&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;div className='md:hidden bg-white rounded-b-lg w-full ' &gt; &lt;div className=' mx-20 justify-between'&gt; { openMenu &amp;&amp; &lt;div className=' flex flex-column items-center space-y-8 py-3'&gt; &lt;Link href="proxy.php?url=/" className=' cusor-pointer '&gt; &lt;div className='no-underline font-semibold text-lg text-black-600 hover:text-orange-600 block cursor-pointer'&gt; Home &lt;/div&gt; &lt;/Link&gt; &lt;Link href="proxy.php?url=/Feed" className=' cusor-pointer '&gt; &lt;div className='no-underline font-semibold text-lg text-black-600 hover:text-orange-600 cursor-pointer'&gt; Feed &lt;/div&gt; &lt;/Link&gt; &lt;Link href="proxy.php?url=/starred" className=' cusor-pointer '&gt; &lt;div className='no-underline font-semibold text-lg text-black-600 hover:text-orange-600 cursor-pointer'&gt; Starred &lt;/div&gt; &lt;/Link&gt; &lt;Link href="proxy.php?url=/creations" className=' cusor-pointer '&gt; &lt;div className='no-underline font-semibold text-lg text-black-600 hover:text-orange-600 cursor-pointer'&gt; Creations &lt;/div&gt; &lt;/Link&gt; &lt;Link href="proxy.php?url=/create" className=' cusor-pointer '&gt; &lt;button className='no-underline bg-green-500 py-2 px-3 rounded-lg font-semibold text-lg text-teal-50 hover:bg-orange-500 cursor-pointer '&gt; Create NFT &lt;/button&gt; &lt;/Link&gt; &lt;/div&gt; } &lt;/div&gt; &lt;/div&gt; &lt;/nav&gt; ) } export default Navbar </code></pre> </div> <p>Now we are done with the components folder and files, now to get to the pages started.<br> Go to your pages folder and open _app.js and paste the following code inside :<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>import '../styles/globals.css' import '@rainbow-me/rainbowkit/styles.css'; import { apiProvider, configureChains, getDefaultWallets, RainbowKitProvider, } from '@rainbow-me/rainbowkit'; import { chain, createClient, WagmiProvider } from 'wagmi'; import Navbar from '../components/Navbar'; import "react-loader-spinner/dist/loader/css/react-spinner-loader.css"; import { useState } from 'react'; import Router from 'next/router'; import Loader from '../components/loader'; const { chains, provider } = configureChains( [chain.mainnet, chain.polygon, chain.polygonMumbai], [ apiProvider.alchemy(process.env.ANKR_ID), apiProvider.fallback() ] ); const { connectors } = getDefaultWallets({ appName: 'My RainbowKit App', chains }); const wagmiClient = createClient({ autoConnect: true, connectors, provider }) function MyApp({ Component, pageProps }) { const[loader,setLoader]= useState(false) Router.events.on("routeChangeStart" , (url) =&gt; { setLoader(true) }) Router.events.on("routeChangeComplete" , (url) =&gt; { setLoader(false) }) return( &lt;div &gt; &lt;WagmiProvider client={wagmiClient}&gt; &lt;RainbowKitProvider chains={chains}&gt; &lt;div className=''&gt; { loader ? ( &lt;Loader/&gt; ) : ( &lt;&gt; &lt;Navbar/&gt; &lt;div className='h-24 w-full'&gt; &lt;/div&gt; &lt;Component {...pageProps} /&gt; &lt;/&gt; ) } &lt;/div&gt; &lt;/RainbowKitProvider&gt; &lt;/WagmiProvider&gt; &lt;/div&gt; ) } export default MyApp </code></pre> </div> <p>This is the main page and this is where other pages are initialized "_<em>app.js</em>"</p> <p><strong>Homepage</strong><br> We will be using the index.js file under the pages folder as the homepage for our dapp.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>import Head from 'next/head' import { ConnectButton } from '@rainbow-me/rainbowkit'; import { useContract, useProvider,useSigner,useAccount,useBalance,useConnect } from 'wagmi' import {MemeForestAddress,ApiUriv} from '../constant' import { useEffect, useState } from "react"; import MEME from '../artifacts/contracts/MemeForest.sol/MemeForest.json' import { createClient } from 'urql' const MemberQuery= ` query { memebers{ Name Adddress TotalMeme StarredMemes Date } } ` const client = createClient({ url: ApiUriv, }) export default function Home(props) { const { data} = useAccount() const person = data?.address; const [name, setName] = useState("") const [Address, setAddress] = useState("") const [loading,setLoading] = useState(false) const [AMember,setAMember] = useState(false) const[loadingpage,setLoadingPage] = useState(false) const provider = useProvider() const { data: signer } = useSigner() const contractWithSigner = useContract({ addressOrName: MemeForestAddress, contractInterface: MEME.abi, signerOrProvider: signer, }) const contractWithProvider = useContract({ addressOrName: MemeForestAddress, contractInterface: MEME.abi, signerOrProvider: provider, }) useEffect(() =&gt; { PageLoad() checkIfAMember(props); }, []); const PageLoad = async () =&gt;{ try { setLoadingPage(true) const delay = ms =&gt; new Promise(res =&gt; setTimeout(res, ms)); await delay(7000); setLoadingPage(false) } catch (e) { console.log(e) } } const joinMembership = async () =&gt; { try { setLoading(true) let _time = new Date().toLocaleString(); if(!name) { alert("Name is not there") } const join = await contractWithSigner.CreateMembers(name,_time) await join.wait() setLoading(false) setAMember(true) checkIfAMember(props); } catch (w) { console.log(w) } } const checkIfAMember = async (props) =&gt; { try { let data = props.members; const addresses = [''] const tx = await Promise.all(data.map(async i =&gt; { addresses.push(i.Adddress) return addresses })); const Address = person.toLowerCase() setAddress(Address); const isThere = addresses.includes(Address) setAMember(isThere) } catch (e) { console.log(e) setAMember(false) } } const renderButton = () =&gt; { if(!AMember) { return ( &lt;div className='flex items-center w-full h-full z-0'&gt; &lt;div className=' flex flex-col-reverse md:flex-row items-center md:justify-between w-full h-full '&gt; &lt;div className='flex flex-column items-center w-full basis-2/5 space-y-6 p-20 mr-4 mt-10'&gt; &lt;div className='flex items-center text-3xl text-center text-black font-bold'&gt; &lt;span&gt;Welcome To NFT &lt;span className='text-green-500'&gt; Air &lt;/span&gt; &lt;/span&gt; &lt;/div&gt; &lt;div className='text-sm text-gray-400'&gt; Register to become a Member &lt;/div&gt; &lt;div className='pt-2 w-full'&gt; &lt;input className='px-2 py-1 h-10 font-semibold text-sm w-full border rounded-xl ' placeholder='Enter your Name' onChange={e =&gt; setName(e.target.value)}/&gt; &lt;/div&gt; &lt;div className='flex flex-col items-center justify-center w-full'&gt; { loading ? &lt;button className='text-lg text-gray-50 flex items-center justify-center font-semibold w-full py-2 bg-white rounded-xl '&gt; &lt;img src="proxy.php?url=/loader.png" alt="loading..." className='w-8 h-8 mt-2' /&gt; &lt;/button&gt; : &lt;button className='text-lg text-gray-50 font-semibold w-full py-2 bg-green-500 hover:bg-gray-50 hover:text-green-500 border hover:border-slate-100 rounded-xl' onClick={joinMembership}&gt; Register &lt;/button&gt; } &lt;span className='text-sm text-gray-400 pt-1'&gt; ------------OR------------&lt;/span&gt; &lt;div className=' text-gray-50 text-xs pt-3 flex items-center justify-center'&gt; &lt;ConnectButton /&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;div className='w-full flex items-center justify-center md:justify-around basis-2/5 md:ml-4 md:mt-0'&gt; &lt;img src='/main-removebg-preview.png' className='w-fit' /&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; ) } if (AMember) { return( &lt;div&gt; &lt;div className='text-lg font-semibold w-full'&gt; { props.members.map((lists,i) =&gt; { return( &lt;div key={i} className='text-lg font-semibold'&gt; { lists.Adddress == Address &amp;&amp; &lt;div className='flex flex-col w-full items-center justify-between space-y-20'&gt; &lt;div className='shadow-sm w-full bg-green-400'&gt; &lt;div className='flex flex-col items-center w-full'&gt; &lt;div className='border border-slate-400 flex flex-col md:flex-row items-center w-full'&gt; &lt;div className="w-full basis-1/5 p-4"&gt; &lt;div className='rounded-lg border border-red-400 h-full p-20' &gt; 01 &lt;/div&gt; &lt;/div&gt; &lt;div className="flex flex-col justify-between w-full basis-4/5 space-y-6 p-10 mr-4 "&gt; &lt;div className=' flex items-center justify-between font-semibold hover:cursor-pointer '&gt; &lt;span className='pb-2 pr-5 text-3xl text-white border-b border-white'&gt; {lists.Name} &lt;/span&gt; &lt;div className='text-sm'&gt; &lt;ConnectButton /&gt; &lt;/div&gt; &lt;/div&gt; &lt;div className='flex justify-between flex-col md:flex-row space-y-6 md:space-y-6 text-lg font-thin hover:cursor-pointer text-white pt-2'&gt; &lt;div className='flex items-end text-sm md:text-lg font-medium '&gt; {lists.Adddress} &lt;/div&gt; &lt;div className='flex flex-col text-lg '&gt; &lt;span className='font-medium'&gt; Date Joined&lt;/span&gt; &lt;span className='font-normal'&gt; {lists.Date}&lt;/span&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;div className='flex flex-col items-center w-full p-10'&gt; &lt;div className='flex flex-col md:flex-row justify-between space-y-6 md:space-x-6 md:space-y-0 hover:cursor-pointer'&gt; &lt;div className='flex flex-col items-center p-10 text-orange-500 hover:bg-gray-50 rounded-lg border-2 border-green-400'&gt; &lt;span className='font-medium '&gt; Number Of Starred Memes&lt;/span&gt; &lt;span className='font-normal'&gt; {lists.StarredMemes}&lt;/span&gt; &lt;/div&gt; &lt;div className='flex flex-col items-center p-10 text-orange-500 hover:bg-gray-50 rounded-lg border-2 border-green-400'&gt; &lt;span className='font-medium'&gt; Number Of Total Memes&lt;/span&gt; &lt;span className='font-normal'&gt; {lists.TotalMeme}&lt;/span&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; } &lt;/div&gt; ) }) } &lt;/div&gt; &lt;/div&gt; ) } } return ( &lt;div&gt; &lt;Head&gt; &lt;title&gt;Home&lt;/title&gt; &lt;meta name="description" content="By Oleanji" /&gt; &lt;link rel="icon" href="proxy.php?url=/favicon.ico" /&gt; &lt;/Head&gt; {renderButton()} &lt;/div&gt; ) } async function GetData() { const data = await client.query(MemberQuery).toPromise() return data.data.memebers } export async function getServerSideProps() { const data = await GetData() return{ props:{ members:data } } } </code></pre> </div> <p>The results </p> <p><a href="proxy.php?url=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%2Fut2j92w2idbxuaeflytg.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fut2j92w2idbxuaeflytg.png" alt="Register" width="800" height="388"></a></p> <p><a href="proxy.php?url=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%2Ffmcm3gnk2m3dgcp2jzkc.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Ffmcm3gnk2m3dgcp2jzkc.png" alt="Dashboard" width="800" height="390"></a></p> <p>Here, we get users to register their address, and in doing so they become members of the dapp and they are able to create art and upload.</p> <p><strong>Feed</strong><br> This shows to everyone regardless of your membership status, but you are only able to view and not react if you are not a member.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>import Head from 'next/head' import { ConnectButton } from '@rainbow-me/rainbowkit'; import { useContract, useProvider,useSigner,useAccount,useBalance,useConnect } from 'wagmi' import {MemeForestAddress,Token, ApiUriv} from '../constant' import { useEffect, useState } from "react"; import MEME from '../artifacts/contracts/MemeForest.sol/MemeForest.json' import 'bootstrap/dist/css/bootstrap.css' import axios from "axios" import { createClient } from 'urql' import { Web3Storage } from 'web3.storage' const MemesQuery= ` query { memes( orderBy : id, orderDirection: desc ) { id MemeInfo Owner IsStarred Stars Likes Date FileType IsDownloadable StarredAddresses LikesAddresses } } ` const MemberQuery= ` query { memebers{ Name Adddress TotalMeme StarredMemes Date } } ` const client = createClient({ url: ApiUriv, }) export default function Feed (props) { const Memeslength = props.memes.length const { data} = useAccount() const person = data?.address; const[loadingStar, setLoadingStar] = useState(false) const[memberDetails,setMemberDetails] = useState([]) const[loadingLike, setLoadingLike] = useState(false) const[loadingLikeId, setLoadingLikeId] = useState(0) const[loadingStarId, setLoadingStarId] = useState(0) const provider = useProvider() const { data: signer} = useSigner() const[loadingpage,setLoadingPage] = useState(false) const contractWithSigner = useContract({ addressOrName: MemeForestAddress, contractInterface: MEME.abi, signerOrProvider: signer, }) const contractWithProvider = useContract({ addressOrName: MemeForestAddress, contractInterface: MEME.abi, signerOrProvider: provider, }) useEffect(() =&gt; { PageLoad(); FechMemeInfo(props); }, []); const PageLoad = async () =&gt;{ try { setLoadingPage(true) const delay = ms =&gt; new Promise(res =&gt; setTimeout(res, ms)); await delay(20000); setLoadingPage(false) } catch (e) { console.log(e) } } const StarMeme = async (id,bool) =&gt;{ try { setLoadingStar(true) setLoadingStarId(id) if (bool == true) { const data= await contractWithSigner.RemoveStarMeme(id) await data.wait() await FechMemeInfo(props); } else { const data= await contractWithSigner.StarMeme(id) await data.wait() await FechMemeInfo(props); } setLoadingStar(false) } catch (e) { console.log(e) } } const download = (e,name) =&gt; { try { const Link = `https://${e}.ipfs.dweb.link/image` axios({ url: Link, //your url method: 'GET', responseType: 'blob', // important }).then((response) =&gt; { const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; link.setAttribute("download", name+".png" ); document.body.appendChild(link); link.click(); }); } catch (error) { console.log(error) } }; const LikeMeme = async (id,bool) =&gt;{ try { setLoadingLike(true) setLoadingLikeId(id) if (bool == true) { const data= await contractWithSigner.UnLikeMeme(id) await data.wait() await FechMemeInfo(props); } else { const data= await contractWithSigner.LikeMeme(id) await data.wait() await FechMemeInfo(props); } setLoadingLike(false) } catch (e) { console.log(e) } } function getAccessToken () { return Token; } function makeStorageClient () { return new Web3Storage({ token: getAccessToken() }) } const FechMemeInfo = async (props) =&gt; { const client = makeStorageClient() let data = props.memes; const tx = await Promise.all(data.map(async i =&gt; { const res = await client.get(i.MemeInfo) if(!res.ok) { return; } const StarAnswer= signer ? await contractWithProvider.WhatDidIStar(i.id,person) : false; const LikeAnswer= signer ? await contractWithProvider.WhatDidILike(i.id,person) : false; let files = await res.files() const info = await axios.get(`https://${files[0].cid}.ipfs.dweb.link`) let List = { Name:info.data.nameOfFile, Description:info.data.DescriptionOfFile, image:info.data.image, Owner: i.Owner, IsStarred:i.IsStarred, NumberOfStars:i.Stars, NumberOfLikes:i.Likes, Date:i.Date, Id :i.id, IsDownloadable : i.IsDownloadable, FileType :i.FileType, DidMemberStarMe: StarAnswer, DidMemberLikeMe:LikeAnswer } return List })); setMemberDetails(tx) } const renderButton = () =&gt; { if(Memeslength == 0) { return ( &lt;div className='flex flex-row items-center justify-center' &gt; { loadingpage ? ( &lt;div className='text-center text-8xl'&gt; &lt;img src="proxy.php?url=/loading.png" alt="loading..." /&gt; &lt;/div&gt; ) : ( &lt;h4 className='text-center'&gt; There are no Memes For Display &lt;/h4&gt; ) } &lt;/div&gt; ) } if (Memeslength&gt;0){ return( &lt;&gt; { loadingpage ? ( &lt;div className='flex flex-row items-center justify-center' &gt; &lt;div className='text-center text-8xl'&gt; &lt;img src="proxy.php?url=/loading.png" alt="loading..." /&gt; &lt;/div&gt; &lt;/div&gt; ) : ( &lt;div className='grid xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 px-5 py-2 ' &gt; { memberDetails.map((card,i) =&gt; { return( &lt;div key={i} className='w-full shadow-md p-3 rounded-3xl bg-gray-50 '&gt; { &lt;div className='flex flex-col' &gt; &lt;div className='group flex flex-row items-center justify-center overflow-hidden rounded-lg ' &gt; &lt;a href={card.File} target='_blank' rel="noreferrer" &gt; { (card.FileType == "img/png") ? ( &lt;img src={`https://${card.image}.ipfs.dweb.link/image`} className='w-full rounded-lg h-36 group-hover:scale-150 transition ease duration-300' alt="..." /&gt; ) : ( &lt;video src={`https://${card.image}.ipfs.dweb.link/image`} className='w-full rounded-lg h-36 group-hover:scale-150 transition ease duration-300' alt="..." width="500px" height="500px" controls="controls"/&gt; ) } &lt;/a&gt; &lt;div className=' hidden p-1 rounded-lg bg-gray-700 text-gray-100 font-medium text-xs group-hover:inline absolute self-start ' &gt; { props.members.map((lists,i) =&gt; { return( &lt;div key={i} &gt; { lists.Adddress == card.Owner &amp;&amp; &lt;div&gt; {lists.Name} &lt;/div&gt; } &lt;/div&gt; ) }) } &lt;/div&gt; &lt;div className='hidden p-1 rounded-lg bg-gray-700 text-gray-100 font-thin text-xs group-hover:inline absolute self-end' &gt; { card.Date } &lt;/div&gt; &lt;/div&gt; &lt;div className='py-2 px-3 border-2 border-gray-500 h-auto mx-2 mt-4 rounded-lg' &gt; &lt;div className='grid grid-rows grid-flow-col gap-1 ' &gt; { card.Name.length &gt; 7 ? ( &lt;div className='flex items-end row-start-2 row-span-2 rounded-lg font-black text-xs ' &gt; {card.Name} &lt;/div&gt; ) : ( &lt;div className='flex items-end row-start-2 row-span-2 rounded-lg font-black text-sm '&gt; {card.Name} &lt;/div&gt; ) } { card.IsDownloadable ? &lt;div className='row-start-2 row-span-2 flex items-center justify-center rounded-lg shadow-md py-2 hover:shadow-xl transition ease ' &gt; &lt;a href={`https://${card.image}.ipfs.dweb.link/image`} download target='_blank' rel="noreferrer" onClick={(e) =&gt;download(card.image,card.Name)}&gt; &lt;img src='./arrow.png' alt='' className='h-5 w-5 mt-1' /&gt; &lt;/a&gt; &lt;/div&gt; : &lt;div className='row-start-2 h-10 row-span-2 flex items-center justify-center rounded-lg py-2 ' &gt; &lt;/div&gt; } &lt;/div&gt; &lt;div className='rounded-md mt-3 text-sm h-auto ' &gt; {card.Description} &lt;/div&gt; &lt;div className='flex flex-row justify-between space-x-1'&gt; &lt;button className='rounded-md border-2 border-black flex mt-3 items-center justify-around h-8 w-24 hover:bg-[#FFFF00] 'onClick={() =&gt; StarMeme(card.Id, card.DidMemberStarMe)}&gt; { ((loadingStarId == card.Id) &amp;&amp; loadingStar ) ? ( &lt;button className='bg-[#FFFF00] rounded-md flex items-center justify-around h-7 w-24'&gt; &lt;h4&gt; &lt;img src="proxy.php?url=/loader.png" alt="loading..." className='w-8 h-8 mt-2' /&gt; &lt;/h4&gt; &lt;/button&gt; ) : ( (card.DidMemberStarMe == true) ? ( &lt;&gt; &lt;img src='./filledStar.png' alt='STAR' className='w-5 h-5' /&gt; {card.NumberOfStars} &lt;/&gt; ) : ( &lt;&gt; &lt;img src='./strokeStar.png' alt='STAR' className='w-5 h-5' /&gt; {card.NumberOfStars} &lt;/&gt; ) ) } &lt;/button&gt; &lt;button className='rounded-md border-2 border-black flex mt-3 items-center justify-around h-8 w-24 hover:bg-[#ff0000] ' onClick={() =&gt; LikeMeme(card.Id, card.DidMemberLikeMe)} &gt; { ((loadingLikeId == card.Id) &amp;&amp; loadingLike) ? ( &lt;button className='rounded-md border-2 border-black flex items-center justify-around h-8 w-24 bg-[#FFFF00] ' &gt; &lt;h4&gt; &lt;img src='./filledStar.png' alt='STAR' className='w-5 h-5' /&gt; &lt;/h4&gt; &lt;/button&gt; ) : ( (card.DidMemberLikeMe == true) ? ( &lt;&gt; &lt;img src='./filledLove.png' alt='STAR' className='w-5 h-5' /&gt; {card.NumberOfLikes} &lt;/&gt; ) : ( &lt;&gt; &lt;img src='./UnfilledLove.png' alt='STAR' className='w-5 h-5' /&gt; {card.NumberOfLikes} &lt;/&gt; ) ) } &lt;/button&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; } &lt;/div&gt; ) }) } &lt;/div&gt; ) } &lt;/&gt; ) } } return ( &lt;div&gt; &lt;Head&gt; &lt;title&gt;Home&lt;/title&gt; &lt;meta name="description" content="By Oleanji" /&gt; &lt;link rel="icon" href="proxy.php?url=/favicon.ico" /&gt; &lt;/Head&gt; &lt;div className='flex flex-col space-y-6'&gt; &lt;div className='flex flex-col items-end pt-3 px-2'&gt; &lt;ConnectButton /&gt; &lt;/div&gt; &lt;div className=''&gt; {renderButton()} &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; ) } async function GetData() { const data = await client.query(MemesQuery).toPromise() return (data.data.memes) } async function MemInfo() { const info = await client.query(MemberQuery).toPromise() return (info.data.memebers) } export async function getServerSideProps() { const data = await GetData() const info = await MemInfo() return{ props:{ memes:data, members:info } } } </code></pre> </div> <p>Result:</p> <p><a href="proxy.php?url=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%2Fsf1kd84xt4uwl5xec277.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fsf1kd84xt4uwl5xec277.png" alt="Feed" width="800" height="388"></a></p> <p><strong>Starred Page</strong></p> <p>This page will contain the list of starred items of a particular member of the dapp (i.e the art you reacted with a star)<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>import Head from 'next/head' import { ConnectButton } from '@rainbow-me/rainbowkit'; import { useContract, useProvider,useSigner,useAccount,useBalance,useConnect } from 'wagmi' import {MemeForestAddress,Token, ApiUriv} from '../constant' import { useEffect, useState } from "react"; import MEME from '../artifacts/contracts/MemeForest.sol/MemeForest.json' import axios from "axios" import { createClient } from 'urql' import { Web3Storage } from 'web3.storage' import { useRouter } from 'next/router'; const MemesQuery= ` query { memes( orderBy : id, orderDirection: desc ) { id MemeInfo Owner IsStarred Stars Likes Date FileType IsDownloadable StarredAddresses LikesAddresses } } ` const MemberQuery= ` query { memebers{ Name Adddress TotalMeme StarredMemes Date } } ` const client = createClient({ url: ApiUriv, }) export default function Starred (props) { const { data} = useAccount() const person = data?.address; const[loadingStarId, setLoadingStarId] = useState(0) const[loadingStar, setLoadingStar] = useState(false) const[DidIStarMeme, SetDidIStarMeme] =useState(false) const [AMember,setAMember] = useState(false) const[memeDetails,setMemeDetails] = useState([]) const[loadingpage,setLoadingPage] = useState(false) const provider = useProvider() const { data: signer} = useSigner() const contractWithSigner = useContract({ addressOrName: MemeForestAddress, contractInterface: MEME.abi, signerOrProvider: signer, }) const contractWithProvider = useContract({ addressOrName: MemeForestAddress, contractInterface: MEME.abi, signerOrProvider: provider, }); const router = useRouter() useEffect(() =&gt; { PageLoad(); checkIfAMember(props); StarredMemes(props); }, []); const PageLoad = async () =&gt;{ try { setLoadingPage(true) const delay = ms =&gt; new Promise(res =&gt; setTimeout(res, ms)); await delay(7000); setLoadingPage(false) } catch (e) { console.log(e) } } const checkIfAMember = async (props) =&gt; { try { let data = props.members; const addresses = [''] const tx = await Promise.all(data.map(async i =&gt; { addresses.push(i.Adddress) return addresses })); const Address = person.toLowerCase() const isThere = addresses.includes(Address) setAMember(isThere) } catch (e) { console.log(e) setAMember(false) } } function getAccessToken () { return Token; } function makeStorageClient () { return new Web3Storage({ token: getAccessToken() }) } const StarredMemes = async (props) =&gt; { const client = makeStorageClient() let data = props.memes; const tx = await Promise.all(data.map(async i =&gt; { const res = await client.get(i.MemeInfo) if(!res.ok) { return; } const StarredAddress = i.StarredAddresses; for (let i = 0; i &lt; StarredAddress.length; i++) { const Address = person.toLowerCase() const CurrentAddress = StarredAddress[i] if(Address == CurrentAddress ){ SetDidIStarMeme(true) } else{ SetDidIStarMeme(false) } } const StarAnswer= await contractWithProvider.WhatDidIStar(i.id,person); let files = await res.files() const info = await axios.get(`https://${files[0].cid}.ipfs.dweb.link`) let List = { Name:info.data.nameOfFile, Description:info.data.DescriptionOfFile, image:info.data.image, Owner: i.Owner, IsStarred:i.IsStarred, NumberOfStars:i.Stars, NumberOfLikes:i.Likes, Date:i.Date, Id :i.id, IsDownloadable : i.IsDownloadable, FileType :i.FileType, DidMemberStarMe: StarAnswer, } return List })); setMemeDetails(tx) } const StarMeme = async (id,bool) =&gt;{ try { setLoadingStar(true) setLoadingStarId(id) if (bool == true) { const data= await contractWithSigner.RemoveStarMeme(id) await data.wait() await FechMemeInfo(props); } else { const data= await contractWithSigner.StarMeme(id) await data.wait() await FechMemeInfo(props); } setLoadingStar(false) } catch (e) { console.log(e) } } const download = (e,name) =&gt; { axios({ url: e, //your url method: 'GET', responseType: 'blob', // important }).then((response) =&gt; { const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; link.setAttribute("download", name+".png" ); document.body.appendChild(link); link.click(); }); }; const gohome = () =&gt; { router.push('/') } const create = () =&gt; { router.push('/create') } const renderButton = () =&gt; { if(!AMember){ return ( &lt;div&gt; { loadingpage ? ( &lt;div className='flex flex-row items-center justify-center text-8xl '&gt; &lt;img src="proxy.php?url=/loading.png" alt="loading..." /&gt; &lt;/div&gt; ) : ( &lt;div className='flex flex-col items-center justify-center space-y-5 '&gt; &lt;div className='text-center font-bold text-lg '&gt; Go Back Home and Register before Seeing Starred Memes &lt;/div&gt; &lt;img src='/sad.png' className='w-1/6'/&gt; &lt;button onClick={gohome} className='no-underline bg-green-500 py-2 px-3 rounded-lg font-bold text-teal-50 hover:bg-orange-500 cursor-pointer ' &gt; Home &lt;/button&gt; &lt;/div&gt; ) } &lt;/div&gt; ) } if(AMember) { if(memeDetails.length == 0) { return ( &lt;div&gt; { loadingpage ? ( &lt;div className='flex flex-row items-center justify-center text-8xl '&gt; &lt;img src="proxy.php?url=/loading.png" alt="loading..." /&gt; &lt;/div&gt; ) : ( &lt;div className='flex flex-col items-center justify-center space-y-5 ' &gt; &lt;div className='text-center font-bold text-lg '&gt; You have No Starred Memes Go back to Create Memes &lt;/div&gt; &lt;img src='/sad.png' className='w-1/6'/&gt; &lt;button onClick={create} className='no-underline bg-green-500 py-2 px-3 rounded-lg font-bold text-teal-50 hover:bg-orange-500 cursor-pointer '&gt; Create Meme &lt;/button&gt; &lt;/div&gt; ) } &lt;/div&gt; ) } if(memeDetails.length &gt; 0){ return( &lt;div className='flex flex-col ' &gt; &lt;h3 className='text-center font-bold text-lg self-center'&gt; YOUR STARRED NFTS ART(S) &lt;/h3&gt; &lt;div className='grid xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 px-5 py-2 ' &gt; { memeDetails.map((card,i) =&gt; { return( &lt;&gt; { (card.DidMemberStarMe == true)&amp;&amp; &lt;div key={i} className='w-full shadow-md p-3 rounded-3xl bg-gray-50 '&gt; &lt;div className='flex flex-col' &gt; &lt;div className='group flex flex-row items-center justify-center overflow-hidden rounded-lg ' &gt; &lt;a href={card.File} target='_blank' rel="noreferrer" &gt; { (card.FileType == "img/png") ? ( &lt;img src={`https://${card.image}.ipfs.dweb.link/image`} className='w-full rounded-lg h-36 group-hover:scale-150 transition ease duration-300' alt="..." /&gt; ) : ( &lt;video src={`https://${card.image}.ipfs.dweb.link/image`} className='w-full rounded-lg h-36 group-hover:scale-150 transition ease duration-300' alt="..." width="500px" height="500px" controls="controls"/&gt; ) } &lt;/a&gt; &lt;div className=' hidden p-1 rounded-lg bg-gray-700 text-gray-100 font-medium text-xs group-hover:inline absolute self-start ' &gt; { props.members.map((lists,i) =&gt; { return( &lt;div key={i} &gt; { lists.Adddress == card.Owner &amp;&amp; &lt;div&gt; {lists.Name} &lt;/div&gt; } &lt;/div&gt; ) }) } &lt;/div&gt; &lt;div className='hidden p-1 rounded-lg bg-gray-700 text-gray-100 font-thin text-xs group-hover:inline absolute self-end' &gt; { card.Date } &lt;/div&gt; &lt;/div&gt; &lt;div className='py-2 px-3 border-2 border-gray-500 h-auto mx-2 mt-4 rounded-lg' &gt; &lt;div className='grid grid-rows grid-flow-col gap-1 ' &gt; { card.Name.length &gt; 7 ? ( &lt;div className='flex items-end row-start-2 row-span-2 rounded-lg font-black text-xs ' &gt; {card.Name} &lt;/div&gt; ) : ( &lt;div className='flex items-end row-start-2 row-span-2 rounded-lg font-black text-sm '&gt; {card.Name} &lt;/div&gt; ) } { card.IsDownloadable ? &lt;div className='row-start-2 row-span-2 flex items-center justify-center rounded-lg shadow-md py-2 hover:shadow-xl transition ease ' &gt; &lt;a href={`https://${card.image}.ipfs.dweb.link/image`} download target='_blank' rel="noreferrer" onClick={(e) =&gt;download(card.image,card.Name)}&gt; &lt;img src='./arrow.png' alt='' className='h-5 w-5 mt-1' /&gt; &lt;/a&gt; &lt;/div&gt; : &lt;div className='row-start-2 h-10 row-span-2 flex items-center justify-center rounded-lg py-2 ' &gt; &lt;/div&gt; } &lt;/div&gt; &lt;div className='rounded-md mt-3 text-sm h-auto ' &gt; {card.Description} &lt;/div&gt; &lt;div className=''&gt; &lt;button className='rounded-md border-2 border-black flex mt-3 items-center justify-around h-8 w-full hover:bg-[#FFFF00] 'onClick={() =&gt; StarMeme(card.Id, card.DidMemberStarMe)}&gt; { ((loadingStarId == card.Id) &amp;&amp; loadingStar ) ? ( &lt;button className='bg-[#FFFF00] rounded-md flex items-center justify-around h-7 w-full'&gt; &lt;h4&gt; &lt;img src="proxy.php?url=/loader.png" alt="loading..." className='w-8 h-8 mt-2' /&gt; &lt;/h4&gt; &lt;/button&gt; ) : ( (card.DidMemberStarMe == true) ? ( &lt;&gt; &lt;img src='./filledStar.png' alt='STAR' className='w-5 h-5' /&gt; {card.NumberOfStars} &lt;/&gt; ) : ( &lt;&gt; &lt;img src='./strokeStar.png' alt='STAR' className='w-5 h-5' /&gt; {card.NumberOfStars} &lt;/&gt; ) ) } &lt;/button&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; } &lt;/&gt; ) }) } &lt;/div&gt; &lt;div className='flex items-center justify-center space-x-3 py-3 w-full '&gt; &lt;img src='/sad.png' className='w-[40px]'/&gt; &lt;div className='px-5 text-center text-sm'&gt; Thats all of your Starred Nft Art(s) &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; ) } } } return ( &lt;div&gt; &lt;Head&gt; &lt;title&gt;Home&lt;/title&gt; &lt;meta name="description" content="By Oleanji" /&gt; &lt;link rel="icon" href="proxy.php?url=/favicon.ico" /&gt; &lt;/Head&gt; &lt;div className='flex flex-col space-y-6'&gt; &lt;div className='flex flex-col items-end pt-3 px-2'&gt; &lt;ConnectButton /&gt; &lt;/div&gt; &lt;div&gt; {renderButton()} &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; ) } async function GetData() { const data = await client.query(MemesQuery).toPromise() return (data.data.memes) } async function MemInfo() { const info = await client.query(MemberQuery).toPromise() return (info.data.memebers) } export async function getServerSideProps() { const data = await GetData() const info = await MemInfo() return{ props:{ memes:data, members:info } } } </code></pre> </div> <p>This shows all your starred items, by checking:</p> <ul> <li>If you are a member</li> <li>how many items have you starred</li> </ul> <p>Result:(if you haven't created any art)</p> <p><a href="proxy.php?url=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%2Fqifbfxp7jfl4bvhlv38k.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fqifbfxp7jfl4bvhlv38k.png" alt="Starred" width="800" height="388"></a></p> <p><strong>Creations Page</strong></p> <p>This page shows the creations of a member of the dapp and shows the reactions of others on it.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>import Head from 'next/head' import { ConnectButton } from '@rainbow-me/rainbowkit'; import { useContract, useProvider,useSigner,useAccount,useBalance,useConnect } from 'wagmi' import {MemeForestAddress,Token, ApiUriv} from '../constant' import { useEffect, useState } from "react"; import MEME from '../artifacts/contracts/MemeForest.sol/MemeForest.json' import 'bootstrap/dist/css/bootstrap.css' import axios from "axios" import { createClient } from 'urql' import { Web3Storage } from 'web3.storage' const MemesQuery= ` query { memes( orderBy : id, orderDirection: desc ) { id MemeInfo Owner IsStarred Stars Likes Date FileType IsDownloadable StarredAddresses LikesAddresses } } ` const MemberQuery= ` query { memebers{ Name Adddress TotalMeme StarredMemes Date } } ` const client = createClient({ url: ApiUriv, }) export default function Feed (props) { const Memeslength = props.memes.length const Memberslength = props.members.length const { data} = useAccount() const person = data?.address; const [Address, setAddress] = useState("") const [memes,setMemes] = useState([]) const [aCreator, setIsACreator] = useState(false) const[loadingStar, setLoadingStar] = useState(false) const[memberDetails,setMemberDetails] = useState([]) const[loadingLike, setLoadingLike] = useState(false) const[loadingLikeId, setLoadingLikeId] = useState(0) const[loadingStarId, setLoadingStarId] = useState(0) const provider = useProvider() const { data: signer} = useSigner() const[loadingpage,setLoadingPage] = useState(false) const contractWithSigner = useContract({ addressOrName: MemeForestAddress, contractInterface: MEME.abi, signerOrProvider: signer, }) const contractWithProvider = useContract({ addressOrName: MemeForestAddress, contractInterface: MEME.abi, signerOrProvider: provider, }) useEffect(() =&gt; { const Newperson = person?.toLocaleLowerCase() setAddress(Newperson); PageLoad(); FechMemeInfo(props); }, []); const PageLoad = async () =&gt;{ try { setLoadingPage(true) const delay = ms =&gt; new Promise(res =&gt; setTimeout(res, ms)); await delay(20000); setLoadingPage(false) } catch (e) { console.log(e) } } const create = () =&gt; { router.push('/create') } const StarMeme = async (id,bool) =&gt;{ try { setLoadingStar(true) setLoadingStarId(id) if (bool == true) { const data= await contractWithSigner.RemoveStarMeme(id) await data.wait() await FechMemeInfo(props); } else { const data= await contractWithSigner.StarMeme(id) await data.wait() await FechMemeInfo(props); } setLoadingStar(false) } catch (e) { console.log(e) } } const download = (e,name) =&gt; { try { const Link = `https://${e}.ipfs.dweb.link/image` axios({ url: Link, //your url method: 'GET', responseType: 'blob', // important }).then((response) =&gt; { const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; link.setAttribute("download", name+".png" ); document.body.appendChild(link); link.click(); }); } catch (error) { console.log(error) } }; const LikeMeme = async (id,bool) =&gt;{ try { setLoadingLike(true) setLoadingLikeId(id) if (bool == true) { const data= await contractWithSigner.UnLikeMeme(id) await data.wait() await FechMemeInfo(props); } else { const data= await contractWithSigner.LikeMeme(id) await data.wait() await FechMemeInfo(props); } setLoadingLike(false) } catch (e) { console.log(e) } } function getAccessToken () { return Token; } function makeStorageClient () { return new Web3Storage({ token: getAccessToken() }) } const FechMemeInfo = async (props) =&gt; { const client = makeStorageClient() let data = props.memes; const tx = await Promise.all(data.map(async i =&gt; { const res = await client.get(i.MemeInfo) if(!res.ok) { return; } const StarAnswer= await contractWithProvider.WhatDidIStar(i.id,person); const LikeAnswer= await contractWithProvider.WhatDidILike(i.id,person); let files = await res.files() const info = await axios.get(`https://${files[0].cid}.ipfs.dweb.link`) let List = { Name:info.data.nameOfFile, Description:info.data.DescriptionOfFile, image:info.data.image, Owner: i.Owner, IsStarred:i.IsStarred, NumberOfStars:i.Stars, NumberOfLikes:i.Likes, Date:i.Date, Id :i.id, IsDownloadable : i.IsDownloadable, FileType :i.FileType, DidMemberStarMe: StarAnswer, DidMemberLikeMe:LikeAnswer } return List })); setMemberDetails(tx); } const renderButton = () =&gt; { if(Memeslength == 0) { return ( &lt;div className='flex flex-row items-center justify-center' &gt; { loadingpage ? ( &lt;div className='text-center text-8xl'&gt; &lt;img src="proxy.php?url=/loading.png" alt="loading..." /&gt; &lt;/div&gt; ) : ( &lt;&gt; &lt;img src='/sad.png' className='w-1/6'/&gt; &lt;h4&gt; There are no Memes For Display &lt;/h4&gt; &lt;/&gt; ) } &lt;/div&gt; ) } if (Memeslength&gt;0){ return( &lt;&gt; { loadingpage ? ( &lt;div className='flex flex-row items-center justify-center' &gt; &lt;div className='text-center text-8xl'&gt; &lt;img src="proxy.php?url=/loading.png" alt="loading..." /&gt; &lt;/div&gt; &lt;/div&gt; ) : ( &lt;div className='flex flex-col ' &gt; &lt;h3 className='text-center font-bold text-lg self-center'&gt; YOUR CREATED NFT ART(S) &lt;/h3&gt; &lt;div className='grid xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 px-5 py-2 ' &gt; { memberDetails.map((card,i) =&gt; { return( &lt;&gt; &lt;div key={i} &gt; { (card.Owner == Address) &amp;&amp; &lt;div className='w-full shadow-md p-3 rounded-3xl bg-gray-50 '&gt; &lt;div className='flex flex-col' &gt; &lt;div className='group flex flex-row items-center justify-center overflow-hidden rounded-lg ' &gt; &lt;a href={card.File} target='_blank' rel="noreferrer" &gt; { (card.FileType == "img/png") ? ( &lt;img src={`https://${card.image}.ipfs.dweb.link/image`} className='w-full rounded-lg h-36 group-hover:scale-150 transition ease duration-300' alt="..." /&gt; ) : ( &lt;video src={`https://${card.image}.ipfs.dweb.link/image`} className='w-full rounded-lg h-36 group-hover:scale-150 transition ease duration-300' alt="..." width="500px" height="500px" controls="controls"/&gt; ) } &lt;/a&gt; &lt;div className=' hidden p-1 rounded-lg bg-gray-700 text-gray-100 font-medium text-xs group-hover:inline absolute self-start ' &gt; { props.members.map((lists,i) =&gt; { return( &lt;div key={i} &gt; { lists.Adddress == card.Owner &amp;&amp; &lt;div&gt; {lists.Name} &lt;/div&gt; } &lt;/div&gt; ) }) } &lt;/div&gt; &lt;div className='hidden p-1 rounded-lg bg-gray-700 text-gray-100 font-thin text-xs group-hover:inline absolute self-end' &gt; { card.Date } &lt;/div&gt; &lt;/div&gt; &lt;div className='py-2 px-3 border-2 border-gray-500 h-auto mx-2 mt-4 rounded-lg' &gt; &lt;div className='grid grid-rows grid-flow-col gap-1 ' &gt; { card.Name.length &gt; 7 ? ( &lt;div className='flex items-end row-start-2 row-span-2 rounded-lg font-black text-xs ' &gt; {card.Name} &lt;/div&gt; ) : ( &lt;div className='flex items-end row-start-2 row-span-2 rounded-lg font-black text-sm '&gt; {card.Name} &lt;/div&gt; ) } { card.IsDownloadable ? &lt;div className='row-start-2 row-span-2 flex items-center justify-center rounded-lg shadow-md py-2 hover:shadow-xl transition ease ' &gt; &lt;a href={`https://${card.image}.ipfs.dweb.link/image`} download target='_blank' rel="noreferrer" onClick={(e) =&gt;download(card.image,card.Name)}&gt; &lt;img src='./arrow.png' alt='' className='h-5 w-5 mt-1' /&gt; &lt;/a&gt; &lt;/div&gt; : &lt;div className='row-start-2 h-10 row-span-2 flex items-center justify-center rounded-lg py-2 ' &gt; &lt;/div&gt; } &lt;/div&gt; &lt;div className='rounded-md mt-3 text-sm h-auto ' &gt; {card.Description} &lt;/div&gt; &lt;div className='flex flex-row justify-between space-x-1'&gt; &lt;button className='rounded-md border-2 border-black flex mt-3 items-center justify-around h-8 w-24 hover:bg-[#FFFF00] 'onClick={() =&gt; StarMeme(card.Id, card.DidMemberStarMe)}&gt; { ((loadingStarId == card.Id) &amp;&amp; loadingStar ) ? ( &lt;button className='bg-[#FFFF00] rounded-md flex items-center justify-around h-7 w-24'&gt; &lt;h4&gt; &lt;img src="proxy.php?url=/loader.png" alt="loading..." className='w-8 h-8 mt-2' /&gt; &lt;/h4&gt; &lt;/button&gt; ) : ( (card.DidMemberStarMe == true) ? ( &lt;&gt; &lt;img src='./filledStar.png' alt='STAR' className='w-5 h-5' /&gt; {card.NumberOfStars} &lt;/&gt; ) : ( &lt;&gt; &lt;img src='./strokeStar.png' alt='STAR' className='w-5 h-5' /&gt; {card.NumberOfStars} &lt;/&gt; ) ) } &lt;/button&gt; &lt;button className='rounded-md border-2 border-black flex mt-3 items-center justify-around h-8 w-24 hover:bg-[#ff0000] ' onClick={() =&gt; LikeMeme(card.Id, card.DidMemberLikeMe)} &gt; { ((loadingLikeId == card.Id) &amp;&amp; loadingLike) ? ( &lt;button className='rounded-md border-2 border-black flex items-center justify-around h-8 w-24 bg-[#FFFF00] ' &gt; &lt;h4&gt; &lt;img src='./filledStar.png' alt='STAR' className='w-5 h-5' /&gt; &lt;/h4&gt; &lt;/button&gt; ) : ( (card.DidMemberLikeMe == true) ? ( &lt;&gt; &lt;img src='./filledLove.png' alt='STAR' className='w-5 h-5' /&gt; {card.NumberOfLikes} &lt;/&gt; ) : ( &lt;&gt; &lt;img src='./UnfilledLove.png' alt='STAR' className='w-5 h-5' /&gt; {card.NumberOfLikes} &lt;/&gt; ) ) } &lt;/button&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; } &lt;/div&gt; &lt;/&gt; ) }) } &lt;/div&gt; &lt;div className='flex items-center justify-center w-full py-4'&gt; &lt;img src='/sad.png' className='w-[40px]'/&gt; &lt;div className='px-5 text-center text-sm'&gt; Thats all of your Created Nft Art(s) &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; ) } &lt;/&gt; ) } } return ( &lt;div&gt; &lt;Head&gt; &lt;title&gt;Home&lt;/title&gt; &lt;meta name="description" content="By Oleanji" /&gt; &lt;link rel="icon" href="proxy.php?url=/favicon.ico" /&gt; &lt;/Head&gt; &lt;div className='flex flex-col space-y-6'&gt; &lt;div className='flex flex-col items-end pt-3 px-2'&gt; &lt;ConnectButton /&gt; &lt;/div&gt; &lt;div className=''&gt; {renderButton()} &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; ) } async function GetData() { const data = await client.query(MemesQuery).toPromise() return (data.data.memes) } async function MemInfo() { const info = await client.query(MemberQuery).toPromise() return (info.data.memebers) } export async function getServerSideProps() { const data = await GetData() const info = await MemInfo() return{ props:{ memes:data, members:info } } } </code></pre> </div> <p><a href="proxy.php?url=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%2Fwfahzp9044d0ac02psgc.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fwfahzp9044d0ac02psgc.png" alt="Creations page" width="800" height="388"></a></p> <p><strong>Create Page</strong></p> <p>This page is used to upload the art of members<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>import Head from 'next/head' import { ConnectButton } from '@rainbow-me/rainbowkit'; import { useContract, useProvider,useSigner,useAccount } from 'wagmi' import {MemeForestAddress, Token, ApiUriv} from '../constant' import { useEffect, useState } from "react"; import MEME from '../artifacts/contracts/MemeForest.sol/MemeForest.json' import { createClient } from 'urql' import { useRouter } from 'next/router'; import { Web3Storage } from 'web3.storage' const MemberQuery= ` query { memebers{ Name Adddress TotalMeme StarredMemes Date } } ` const client = createClient({ url: ApiUriv, }) export default function Create (props) { const { data} = useAccount() const person = data?.address; const [AMember,setAMember] = useState(false) const [nameOfFile, setNameOfFile] = useState("") const [DescriptionOfFile, setDescriptionOfFile] = useState("") const [Image, setImage] = useState() const [viewing,setViewing] = useState() const[loading, setLoading] = useState(false) const[IsVideo, setIsVideo] = useState(false) const[IsImage, setIsImage] = useState(false) const[IsDownloadable, SetIsDownloadable] = useState(false) const[loadingpage,setLoadingPage] = useState(false) const[valueExtension, setValueExtension] = useState("") const [numberOfLoading, setNumberOfLoading] = useState(3) const { data: signer, isError, isLoading } = useSigner() const contractWithSigner = useContract({ addressOrName: MemeForestAddress, contractInterface: MEME.abi, signerOrProvider: signer, }) const router = useRouter() useEffect(() =&gt; { PageLoad() checkIfAMember(props); }, []); const PageLoad = async () =&gt;{ try { setLoadingPage(true) const delay = ms =&gt; new Promise(res =&gt; setTimeout(res, ms)); await delay(7000); setLoadingPage(false) } catch (e) { console.log(e) } } const checkIfAMember = async (props) =&gt; { try { let data = props.members; const addresses = [''] const tx = await Promise.all(data.map(async i =&gt; { addresses.push(i.Adddress) return addresses })); const Address = person.toLowerCase() const isThere = addresses.includes(Address) setAMember(isThere) } catch (e) { console.log(e) setAMember(false) } } const CreateMemes = async (memeInfo, valueExt) =&gt; { try { let time = new Date().toLocaleString(); const create = await contractWithSigner.CreateMemeItems(memeInfo,person,time,valueExt,IsDownloadable) setNumberOfLoading(1) await create.wait() setLoading(false) Feed(); } catch (error) { console.log(error) } } function getAccessToken () { return Token; } function makeStorageClient () { return new Web3Storage({ token: getAccessToken() }) } const Uploading = async (valueExt) =&gt; { try { if(!nameOfFile) { alert("Name of Meme is not there") } if(!DescriptionOfFile) { alert("Description of Meme is not there") } if(!Image) { alert("Put in a picture of your meme") } if(nameOfFile &amp;&amp; DescriptionOfFile ) { setLoading(true) const client = makeStorageClient() const file = new File([Image], 'image', { type: 'img/png' }) const cid = await client.put([file]) const data = JSON.stringify ({ nameOfFile, DescriptionOfFile, image:cid }) setNumberOfLoading(2) const blob = new Blob([data], { type: 'application/json' }) const files = [ new File([blob], 'MemeInfo') ] const MemeInfo = await client.put(files) CreateMemes(MemeInfo,valueExt); } } catch (e) { console.log(e) } } const gohome = () =&gt; { router.push('/') } const Feed = () =&gt; { router.push('/Feed') } function OnFileChange(e) { try { const file = e.target.files[0] const fie = e.target.files[0].name if(fie){ const extension = fie.slice((Math.max(0, fie.lastIndexOf(".")) || Infinity) + 1); if (extension==="mp4" || extension==="mkv" || extension ==="avi" || extension ==="m4a"){ setIsVideo(true); setIsImage(false); setValueExtension("img/mp4") } else{ setIsVideo(false); setIsImage(true); setValueExtension("img/png") } } if(file){ const image = URL.createObjectURL(file) setViewing(image) let reader = new FileReader() reader.onload = function () { if(reader.result){ setImage(Buffer.from(reader.result)) } } reader.readAsArrayBuffer(file) } } catch (error) { console.log(error ) } } const checkbox = () =&gt; { let value = IsDownloadable; SetIsDownloadable (!value) } const renderButton = () =&gt;{ if(!AMember){ return ( &lt;div&gt; { loadingpage ? ( &lt;div className='flex flex-row items-center justify-center text-8xl '&gt; &lt;img src="proxy.php?url=/loading.png" alt="loading..." /&gt; &lt;/div&gt; ) : ( &lt;div className='flex flex-col items-center justify-center '&gt; &lt;div className='text-center font-bold text-lg '&gt; Go Back Home and Register before Uploading Memes &lt;/div&gt; &lt;img src='/sad.png' className='w-1/6'/&gt; &lt;button onClick={gohome} className='no-underline bg-green-500 py-2 px-3 rounded-lg font-bold text-teal-50 hover:bg-orange-500 cursor-pointer ' &gt; Home &lt;/button&gt; &lt;/div&gt; ) } &lt;/div&gt; ) } if(AMember){ return( &lt;&gt; { loadingpage ? ( &lt;div className='flex flex-row items-center justify-center' &gt; &lt;div className='text-center text-8xl'&gt; &lt;img src="proxy.php?url=/loading.png" alt="loading..." /&gt; &lt;/div&gt; &lt;/div&gt; ) : ( &lt;div className='flex flex-col items-center justify-center w-full'&gt; &lt;h3 className='text-center font-bold text-lg self-center'&gt; CREATE YOUR NFT ART AND SHOW THE WORLD &lt;/h3&gt; &lt;div className='flex flex-col md:flex-row items-center justify-center py-2 w-4/5 space-y-8 md:space-x-8'&gt; &lt;div className=' w-full self-start top-0 py-2'&gt; &lt;div className='flex flex-col space-y-4 items-center justify-start p-3 '&gt; &lt;div className=' self-start font-semibold' &gt; Name: &lt;/div&gt; &lt;input type='text' placeholder='Name Of Meme' onChange={e =&gt; setNameOfFile(e.target.value)} className='p-1 border-2 border-slate-500 mx-4 rounded-lg w-3/4 self-start text-sm ' /&gt; &lt;/div&gt; &lt;div className='flex flex-col space-y-4 items-center justify-start p-3 '&gt; &lt;div className=' self-start font-semibold'&gt; Description: &lt;/div&gt; &lt;input type='text' placeholder='Describe your meme' onChange={e =&gt; setDescriptionOfFile(e.target.value)} className='p-1 border-2 border-slate-500 mx-4 rounded-lg w-3/4 self-start text-sm ' /&gt; &lt;/div&gt; &lt;/div&gt; &lt;div className='py-2 w-full flex flex-col items-center justify-center'&gt; { viewing? &lt;div className=' border-2 border-slate-400 '&gt; { IsImage? ( &lt;img src={viewing} alt='Your Image' className='w-32 m-4'/&gt; ) : ( &lt;video src={viewing} width="500px" height="500px" /&gt; ) } &lt;/div&gt; : &lt;div className='w-full h-auto border-2 border-slate-400 flex items-center justify-center '&gt; &lt;img src='/empty.png' alt='No image Here' className='w-48 m-4'/&gt; &lt;/div&gt; } &lt;div className='flex flex-row space-x-3 items-center justify-start p-3 w-full'&gt; &lt;div className='font-semibold'&gt; IsDownloadable ? &lt;/div&gt; &lt;input type='checkbox' onChange={() =&gt; checkbox() } /&gt; &lt;/div&gt; &lt;div className='flex flex-row space-x-3 items-center justify-start p-3 w-full '&gt; &lt;div className='font-semibold' &gt; File: &lt;/div&gt; &lt;input type='file' onChange={OnFileChange} className='p-1 border-2 border-slate-500 mx-4 rounded-lg w-full text-sm ' /&gt; &lt;/div&gt; { loading ? ( &lt;button className=' flex items-center justify-center text-center w-full border border-slate-600 border-hidden px-2 py-2 font-semibold text-gray-50 text-lg mt-4 mx-4 bg-green-500 rounded-lg space-x-3 '&gt; &lt;img src="proxy.php?url=/loader.png" alt="loading..." className='w-8 h-8 ' /&gt; &lt;span &gt; {numberOfLoading} &lt;/span&gt; &lt;/button&gt; ) : ( &lt;button onClick={() =&gt; Uploading(valueExtension)} className='text-center w-full border border-slate-600 border-hidden px-2 py-2 font-semibold text-gray-50 text-sm mt-4 mx-4 bg-green-500 hover:text-green-500 hover:bg-white hover:border hover:border-slate-500 rounded-lg' &gt; Create Meme &lt;/button&gt; ) } &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; ) } &lt;/&gt; ) } } return ( &lt;div&gt; &lt;Head&gt; &lt;title&gt;Home&lt;/title&gt; &lt;meta name="description" content="By Oleanji" /&gt; &lt;link rel="icon" href="proxy.php?url=/favicon.ico" /&gt; &lt;/Head&gt; &lt;div className='flex flex-col space-y-6'&gt; &lt;div className='flex flex-col items-end pt-3 px-2'&gt; &lt;ConnectButton /&gt; &lt;/div&gt; &lt;div className=''&gt; {renderButton()} &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; ) } async function MemInfo() { const info = await client.query(MemberQuery).toPromise() return (info.data.memebers) } export async function getServerSideProps() { const info = await MemInfo() return{ props:{ members:info } } } </code></pre> </div> <p>Result: </p> <p><a href="proxy.php?url=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%2Fjuj3l7doojg8x4eb1ibk.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fjuj3l7doojg8x4eb1ibk.png" alt=" " width="800" height="449"></a></p> <p>You give a name and write description for your art before uploading your it.</p> <h2> TESTING </h2> <p>To run this project open your terminal with the directory pointing to this project and run<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>yarn dev </code></pre> </div> <p>This should reun your dapp on this site "<a href="proxy.php?url=http://localhost:3000/" rel="noopener noreferrer">http://localhost:3000/</a>"</p> <p>Check it out and if you run into any errors then write a comment below.</p> <p>We are finally done with all the tasks to do, I hope by now your drink or snack is almost finished ;) If so, go get another.</p> <p>Congratulations!!!!!!!!!!!!!!!!!!!!πŸŽ‰πŸŽ‰πŸš€πŸš€πŸ’–πŸŽŠ you have finished building your Fullstack NFT AIR Dapp.</p> <p>Now we are done with all</p> <ol> <li>Create a nextJs application βœ…</li> <li> Install the necessary dependencies βœ…</li> <li> Write our smart contract βœ…</li> <li> Test the contract βœ…</li> <li> Deploy the Contract βœ…</li> <li> Create and connect your Project with your subgraph βœ…</li> <li> Install more dependencies βœ…</li> <li> Getting assets (Pictures) used in the projectβœ…</li> <li> Creating Pages, Components and writing Queries (i.e wallet connection, contract interaction, data retrieval from the graph ectera)</li> <li>Testing and Running. βœ…</li> <li>Create and Upload an art.</li> </ol> <h2> Create and Upload Art. </h2> <p>Go to the create page and create your art πŸŽ‰πŸŽ‰πŸš€πŸš€</p> beginners javascript webdev blockchain