<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Apps - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Apps - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 09 May 2026 14:06:08 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/apps-tag/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ The Apple Code Signing Handbook ]]>
                </title>
                <description>
                    <![CDATA[ In this handbook, I’ll demystify the Apple app code signing process. Apple's ecosystem is powerful, but its distribution mechanisms – with various identifiers, certificates, and profiles – can appear complex. This guide attempts to make that journey ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/apple-code-signing-handbook/</link>
                <guid isPermaLink="false">68489084490c709f6b3070ed</guid>
                
                    <category>
                        <![CDATA[ Apple ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ macOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sravan Karuturi ]]>
                </dc:creator>
                <pubDate>Tue, 10 Jun 2025 20:07:32 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1749585600223/49e9c922-0b5d-4a98-a619-eedfd7a8b617.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this handbook, I’ll demystify the Apple app code signing process. Apple's ecosystem is powerful, but its distribution mechanisms – with various identifiers, certificates, and profiles – can appear complex. This guide attempts to make that journey more manageable and straightforward for you.</p>
<p>Throughout this handbook, you will learn how to:</p>
<ul>
<li><p>Correctly establish and manage an app's unique identity.</p>
</li>
<li><p>Understand the roles of different Apple developer certificates and how to create and manage them.</p>
</li>
<li><p>Differentiate between various types of provisioning profiles and know when to use each one.</p>
</li>
</ul>
<p>This guide is geared towards new developers who want to learn how the code signing process works, but it should also be useful experienced developers who want or need to refresh their memory.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>While there are no hard prerequisites to understanding the certificates, bundles, and provisioning profiles for distributing on Apple platforms, it helps to have an Apple developer account to follow along.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-app-ids-bundle-ids-your-apps-identity">App IDs, Bundle IDs – Your App’s Identity</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-understanding-distribution-a-deep-dive-into-certificates">Understanding Distribution: A Deep Dive into Certificates</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-bridge-between-everything-provisioning-profiles">Bridge between everything: Provisioning Profiles</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-device-management-development-and-ad-hoc-builds">Device management – Development and Ad Hoc Builds</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-possibilities-enabling-capabilities-and-services">Possibilities: Enabling Capabilities and Services</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-app-ids-bundle-ids-your-apps-identity"><strong>App IDs, Bundle IDs — Your App’s Identity</strong></h2>
<p>The Bundle ID and the corresponding App ID registered with Apple form the basis of an application’s identity. Establishing these correctly from the beginning is very important, as errors or misconfigurations here can lead to significant complications down the line, particularly once you’ve submitted your app to App Store Connect.</p>
<h3 id="heading-understanding-cfbundleidentifier-bundle-id">Understanding <code>CFBundleIdentifier</code> (Bundle ID)</h3>
<h4 id="heading-what-is-the-bundle-id">What is the “Bundle ID”?</h4>
<p>Think of the Bundle ID as a unique name or a fingerprint for your app. The <code>CFBundleIdentifier</code>, more commonly known as the <strong>Bundle ID</strong>, is a string that uniquely identifies your application.</p>
<p>This identifier is not just a name – it serves multiple crucial purposes.</p>
<ul>
<li><p>The operating system relies on it to apply specific preferences and settings to an app.</p>
</li>
<li><p>This is used to launch the application from other apps etc.</p>
</li>
<li><p>It plays an essential role in the validation of an app's code signature, ensuring the app's integrity and authenticity.</p>
</li>
<li><p>The Bundle ID defined in an app's Info.plist file must exactly match the Bundle ID registered for the app in App Store Connect for successful submission and distribution.</p>
</li>
</ul>
<p>The Bundle ID string must adhere to specific character limitations: it can only contain alphanumeric characters <code>A-Z, a-z, 0-9</code>, hyphens <code>-</code>, and periods <code>.</code>. It's important to note that Bundle IDs are treated as <strong>case-insensitive</strong> by the system.</p>
<h3 id="heading-how-to-choose-and-format-your-bundle-id-reverse-dns-and-best-practices">How to Choose and Format Your Bundle ID (Reverse-DNS and Best Practices)</h3>
<p>Apple highly recommends, and it is standard practice, to use a reverse-DNS (Domain Name System) format for Bundle IDs.</p>
<p>A common example would be <code>com.yourcompanyname.appname</code>. This convention leverages the global uniqueness of domain names to help ensure the global uniqueness of Bundle IDs.</p>
<p>If an organization uses its unique domain name (for example, <code>sravan.gg</code> becomes <code>gg.sravan</code> ) as the prefix, and the app name is unique within that organization, the resulting Bundle ID (for example, <code>gg.sravan.mycoolapp</code> ) is highly likely to be unique worldwide.</p>
<p><strong>Sidenote</strong>: While Xcode won’t stop you from creating something like <code>com.google.mapping</code> or something like that even if you don’t work at Google, this will most likely get rejected when it goes through the AppStore review process. This is because this implies ownership of that domain. So, while it’s technically possible when starting out, you shouldn’t use domains that don’t belong to you.</p>
<p>The fundamental nature of the Bundle ID as a unique, system-wide identifier – coupled with its immutability after an app is first uploaded to App Store Connect – means that you should treat its selection with the same seriousness as choosing a <strong>permanent, unchangeable identifier</strong> for a critical entity. A mistake in the Bundle ID after this point can necessitate creating an entirely new app listing on the App Store.</p>
<h3 id="heading-app-ids-in-the-apple-developer-portal-explicit-vs-wildcard">App IDs in the Apple Developer Portal: Explicit vs. Wildcard</h3>
<h4 id="heading-which-one-do-you-need">Which One Do You Need?</h4>
<p>In the Apple Developer Portal, developers register an "App ID." This App ID is a record that links one or more applications from a single development team to specific app services (capabilities) and is used in provisioning profiles. We’ll learn more about this in the following sections.</p>
<p>There are two main types of App IDs:</p>
<ul>
<li><p><strong>Explicit App ID:</strong> This type is used for a single application. The Bundle ID specified within an explicit App ID must be an exact match for the CFBundleIdentifier in the app's Info.plist file (for example, <code>com.mycompany.myapp</code>). Explicit App IDs are required for apps that use many of Apple's specific services and capabilities, such as In-App Purchases (which are enabled by default for explicit App IDs), Push Notifications, iCloud, HealthKit, and Sign in with Apple.</p>
</li>
<li><p><strong>Wildcard App ID:</strong> This type can be used for a set of applications that share a common Bundle ID prefix. It contains an asterisk (*) as the last part of its Bundle ID string (for example, <code>com.mycompany.*</code>). This wildcard App ID would match any app whose Bundle ID starts with <code>com.mycompany.</code>, such as <a target="_blank" href="http://com.mycompany.app"><code>com.mycompany.app</code></a> or <code>com.mycompany.utility</code>. But you can’t use wildcard App IDs if the app requires services or capabilities that mandate an explicit App ID.</p>
</li>
</ul>
<p>The choice between an explicit and a wildcard App ID has significant implications. The App ID acts as a central registration point, and the capabilities are "enabled" for this registration – more on capabilities later in this handbook.</p>
<p>You can think of an explicit App ID as a specific key designed to unlock extra "keyholes" (capabilities). A wildcard App ID, being more generic, might not fit these extra keyholes. If you choose a wildcard App ID initially for convenience, but you need a feature requiring an explicit App ID (like Push Notifications) later, you’ll be forced to create a new explicit App ID and reconfigure associated settings and provisioning profiles.</p>
<p>So, make sure you carefully consider your current and future app features when selecting an App ID type. The following table provides a quick comparison**.**</p>
<p>My personal recommendation is always go with explicit App Ids unless you need the flexibility of wildcard app ids.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Feature</strong></td><td><strong>Explicit App ID</strong></td><td><strong>Wildcard App ID</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Bundle ID Match</strong></td><td>Exact match (for example, <a target="_blank" href="http://com.foo.bar">com.foo.bar</a>)</td><td>Suffix match (for example, <a target="_blank" href="http://com.foo">com.foo</a>.*)</td></tr>
<tr>
<td><strong>Use Case</strong></td><td>Single app</td><td>Set of apps with similar base ID</td></tr>
<tr>
<td><strong>Capabilities</strong></td><td>Supports all capabilities</td><td>Limited (cannot use services requiring explicit IDs)</td></tr>
<tr>
<td><strong>Uniqueness</strong></td><td>Globally unique identifier for one specific app</td><td>Identifies a group of apps</td></tr>
</tbody>
</table>
</div><h3 id="heading-step-by-step-how-to-register-your-app-id-in-the-apple-developer-portal">Step-by-Step: How to Register Your App ID in the Apple Developer Portal</h3>
<p>To register an App ID, an you’ll need an <strong>Apple Developer Program membership</strong>. Also, the actions must be performed by someone with an Account Holder or Admin role.</p>
<p>The process is as follows:</p>
<ol>
<li><p>Sign in to the Apple Developer Portal and navigate to "Certificates, Identifiers &amp; Profiles," then select "Identifiers" from the sidebar.</p>
</li>
<li><p>Click the “Add button (+)” to create a new identifier.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748642247245/a24b527f-e810-4a9c-b75a-dcd3d189b1d1.png" alt="Picture depicting the Add button" class="image--center mx-auto" width="1130" height="404" loading="lazy"></p>
</li>
<li><p>Select "App IDs" from the list of options and click "Continue."</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748642283885/851f64f3-e608-4fb7-9f31-bd30adb64beb.png" alt="851f64f3-e608-4fb7-9f31-bd30adb64beb" class="image--center mx-auto" width="1628" height="704" loading="lazy"></p>
</li>
<li><p>Make sure that the "App" type is selected (it usually is by default) and click "Continue."</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748642318142/a7b28529-bbe6-4240-953e-836de3e948ac.png" alt="App type selection" class="image--center mx-auto" width="1526" height="766" loading="lazy"></p>
</li>
<li><p>Enter a "Description" for the App ID. This is for your reference within the portal (for example, "My very cool App ID").</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748642392862/a5322cf5-3d75-4b0b-93bf-d46dd1ce8afe.png" alt="App Id registration screen" class="image--center mx-auto" width="2446" height="698" loading="lazy"></p>
</li>
<li><p>Choose the "App ID Type": "Explicit" or "Wildcard."</p>
</li>
<li><p>For an "Explicit App ID," enter the exact Bundle ID that will be used in your Xcode project (for example, <code>com.yourcompany.yourapp</code>). For a "Wildcard App ID," enter a Bundle ID suffix ending with an asterisk (for example, <code>com.yourcompany.*</code>).</p>
</li>
<li><p>Scroll down to the "Capabilities" section and select the checkboxes for any app services your app will use. Some capabilities might require further configuration at this stage or later. (Again, we’ll cover app capabilities in more detail later on).</p>
</li>
<li><p>Click "Continue," review all the details carefully, and then click "Register" to finalize the App ID creation.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748642432661/2052a435-ed0e-404a-9178-7d6541fc9421.png" alt="Confirm the App ID screen" class="image--center mx-auto" width="2486" height="708" loading="lazy"></p>
</li>
</ol>
<h3 id="heading-how-to-manage-your-bundle-id-xcode-app-store-connect-and-the-point-of-no-return">How to Manage Your Bundle ID: Xcode, App Store Connect, and the Point of No Return</h3>
<p>The Bundle ID specified in an Xcode project is critical. To set it:</p>
<ol>
<li><p>In the Xcode project navigator, select the target for your app.</p>
</li>
<li><p>Open the "Signing &amp; Capabilities" tab.</p>
</li>
<li><p>Expand the "Signing" section.</p>
</li>
<li><p>In the "Bundle Identifier" text field, enter the Bundle ID. This identifier must precisely match the Bundle ID associated with an explicit App ID registered in the Developer Portal, or conform to the pattern of a wildcard App ID if applicable.</p>
</li>
</ol>
<p>It's important to understand the difference between the "Bundle ID" (or <code>CFBundleIdentifier</code>) in the Xcode project and the "App ID" registered in the Developer Portal. The "App ID" in the developer portal is an entity that <em>contains</em> a “Bundle ID” string (either explicit or wildcard). The string in your Xcode project's "Bundle Identifier" field must match this contained string.</p>
<p>When preparing for distribution via TestFlight or the App Store, you’ll need to create an app record in App Store Connect. The Bundle ID you enter during this app record creation must exactly match the Bundle ID in the Xcode project.</p>
<h4 id="heading-a-critical-warning-immutability-after-first-upload">A Critical Warning: Immutability After First Upload</h4>
<p>This is a point of no return: Once you upload a build of an app to App Store Connect, the Bundle ID for that app record <strong>cannot be changed</strong>.</p>
<p>In addition, after an upload, you can’t delete the associated explicit App ID registered in the Developer Portal. This immutability highlights the need for <em>careful planning and verification</em> of the Bundle ID before any uploads occur.</p>
<p>If you prefer programmatic management or automation, the App Store Connect API provides resources for managing Bundle IDs. You can <a target="_blank" href="https://developer.apple.com/documentation/appstoreconnectapi">read more on that here</a>.</p>
<h2 id="heading-understanding-distribution-a-deep-dive-into-certificates"><strong>Understanding Distribution: A Deep Dive into Certificates</strong></h2>
<h3 id="heading-what-are-certificates">What are Certificates?</h3>
<p>Certificates are digital credentials that verify a <strong>developer's identity</strong> – that is, you – to Apple and, by extension, to the app users.</p>
<p>They are fundamental to Apple's code signing process, which is mandatory for all apps to ensure they originate from a <strong>known source</strong> and have not been tampered with since being signed.</p>
<h3 id="heading-what-is-code-signing-ensuring-trust-and-integrity">What is Code Signing: Ensuring Trust and Integrity</h3>
<p>Code signing is you as a developer signing the app with your signature. It is the process of attaching a digital signature to an app's code. This signature assures users of two key things:</p>
<ol>
<li><p><strong>Authenticity:</strong> The app was created by an identified Apple developer (an individual or a team).</p>
</li>
<li><p><strong>Integrity:</strong> The app's code has not been altered or corrupted since it was signed by the developer.</p>
</li>
</ol>
<p>The process involves using a private key, securely held by the developer (you), to create the signature. The corresponding public key, embedded within the developer's certificate (issued by Apple), is used by the system to verify this signature.</p>
<p>This system of identity verification and integrity checking is crucial. The developer's certificate, issued by Apple as a Certificate Authority (CA), vouches for their identity. The code signing process, using hashing and encryption, ensures that any modification to the code after signing would invalidate the signature.</p>
<p>For app developers, benefits of code signing include removing warnings on macOS for apps distributed outside the Mac App Store, providing a smoother user experience. It is a mandatory requirement for listing applications on any of Apple's App Stores. It also enhances security of the app as it acts as a deterrent against malicious tampering.</p>
<h3 id="heading-types-of-certificates-development-distribution-and-developer-id">Types of Certificates: Development, Distribution, and Developer ID</h3>
<p>Apple provides different types of certificates for various stages of development and methods of distribution. Each of them has a distinct role to play throughout the app development process.</p>
<h4 id="heading-1-development-certificates-for-example-apple-development">1. Development Certificates (for example, "Apple Development"):</h4>
<ul>
<li><p><strong>Purpose:</strong> Used to sign apps during the development phase, allowing them to be installed and run on a limited number of <em>registered test devices</em> and simulators for debugging and testing.</p>
</li>
<li><p><strong>Identifies:</strong> Typically identifies an individual developer through their developer ID.</p>
</li>
<li><p><strong>Used with:</strong> Development provisioning profiles – more on this later.</p>
</li>
</ul>
<h4 id="heading-2-distribution-certificates-for-example-apple-distribution">2. Distribution Certificates (for example, "Apple Distribution"):</h4>
<ul>
<li><p><strong>Purpose:</strong> Used to sign apps intended for distribution, either through Ad Hoc methods (to a limited set of <em>registered testers</em>) or for submission to the App Store.</p>
</li>
<li><p><strong>Identifies:</strong> The development team via the team identifier.</p>
</li>
<li><p><strong>Use Cases:</strong></p>
<ol>
<li><p><strong>App Store:</strong> For signing the final version of an app that will be uploaded to App Store Connect for TestFlight beta testing or release on the App Store (iOS, macOS, tvOS, watchOS). These are used with App Store provisioning profiles – more on this later.</p>
</li>
<li><p><strong>Ad Hoc:</strong> For signing apps that will be distributed to a <em>limited number of registered test devices outside of the App Store or TestFlight</em>. These are used with Ad Hoc provisioning profile. More on this later.</p>
</li>
</ol>
</li>
</ul>
<h4 id="heading-3-developer-id-certificates-for-mac-apps-distributed-outside-the-mac-app-store">3. Developer ID Certificates (for Mac apps distributed outside the Mac App Store):</h4>
<ul>
<li><p><strong>Purpose:</strong> Specifically for macOS developers who wish to distribute their applications directly to users (for example, from their own website) rather than through the Mac App Store. Gatekeeper on macOS recognizes apps signed with a Developer ID certificate, assuring users that the app is from a known developer and has not been tampered with.</p>
</li>
<li><p><strong>Types:</strong></p>
<ol>
<li><p><strong>Developer ID Application:</strong> Used to sign the Mac application bundle (.app) itself.</p>
</li>
<li><p><strong>Developer ID Installer:</strong> Used to sign a Mac Installer Package (.pkg) that contains the signed application.</p>
</li>
<li><p><strong>Limit:</strong> Developers can create up to five Developer ID Application certificates and up to five Developer ID Installer certificates.</p>
</li>
</ol>
</li>
</ul>
<p>The following table summarizes these certificate types:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Certificate Type</strong></td><td><strong>Issued To</strong></td><td><strong>Primary Purpose</strong></td><td><strong>Used With Provisioning Profile Type</strong></td><td><strong>Key Use Cases</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Apple Development</td><td>Individual Dev ID</td><td>Develop &amp; debug on registered devices</td><td>Development</td><td>Xcode builds for local testing, running on personal/team test devices.</td></tr>
<tr>
<td>Apple Distribution</td><td>Team ID</td><td>Submit app to App Store / Ad Hoc distribution</td><td>App Store, Ad Hoc</td><td>Final builds for TestFlight, App Store submission, or QA/client Ad Hoc builds.</td></tr>
<tr>
<td>Developer ID Application</td><td>Team ID</td><td>Sign Mac app for distribution outside Mac App Store</td><td><strong>Developer ID Provisioning</strong> <strong>Profile</strong> if the app utilizes specific capabilities (e.g., Push Notifications, Associated Domains).</td><td>Distributing Mac software directly to users (for example, from website).</td></tr>
<tr>
<td>Developer ID Installer</td><td>Team ID</td><td>Sign Mac Installer Pkg for distribution outside Mac App Store</td><td>N/A. (The app inside the package may need a profile).</td><td>Distributing Mac software in a .pkg installer directly to users.</td></tr>
<tr>
<td>APNs / Service Keys (.p8)</td><td>Team ID</td><td>Secure communication with specific Apple services</td><td>N/A for app signing</td><td>Push Notifications, MusicKit, DeviceCheck and so on. (Token-based authentication)</td></tr>
</tbody>
</table>
</div><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748216973656/76df3f64-c84e-4195-a092-37c1143d8b1b.png" alt="Create a new certificate screen in App Store Connect" class="image--center mx-auto" width="1768" height="1384" loading="lazy"></p>
<h3 id="heading-how-to-create-an-apple-certificate-an-overview">How to Create an Apple Certificate – An Overview</h3>
<p>Here’s a general outline of how you create an Apple Certificate:</p>
<ul>
<li><p>Generate a Certificate Signing Request (CSR) on your Mac. (Yes you need a mac.)</p>
</li>
<li><p>You upload this CSR in AppStoreConnect as a part of creating the certificate.</p>
</li>
<li><p>Download the certificate from AppStoreConnect once it’s issued.</p>
</li>
<li><p>Install the certificate into your Keychain.</p>
</li>
</ul>
<p>Now we’ll go through each step in more detail. This part is very important, since we have to save some of the files generated locally or we lose the ability to transfer these certificates. This would mean revoking and re-issuing certificates (I have done this more times than I’d like to admit).</p>
<h4 id="heading-how-to-create-a-certificate-signing-request-csr">How to Create a Certificate Signing Request (CSR)</h4>
<p>A Certificate Signing Request (CSR) is a fancy name for an encrypted block of text containing information about who’s requesting the certificate (like your name and the public key). These are widely used in the cryptography world.</p>
<p>For our purposes, you’ll generate a CSR on your Mac and then submit it to Apple to request a digital certificate. The CSR generation process also creates a new public/private key pair on the Mac – the private key is stored in Keychain Access and is used for the eventual code signing.</p>
<p>To create a CSR using Keychain Access on macOS:</p>
<ol>
<li><p>Launch Keychain Access (you can find it at <code>/Applications/Utilities/</code> or use spotlight).</p>
</li>
<li><p>From the menu bar, choose Keychain Access &gt; Certificate Assistant &gt; Request a Certificate From a Certificate Authority.... (Here the Certificate Authority would be Apple).</p>
</li>
<li><p>In the dialog, enter your email address and a common name for the key (for example, "My Mac Key" or "[Your Name] Dev Key"). This name is primarily for your identification in the Keychain.</p>
</li>
<li><p>Leave the "CA Email Address" field empty – we won’t email it to the Certificate Authority (Apple).</p>
</li>
<li><p>Select the "Saved to disk" option and click "Continue".</p>
</li>
<li><p>Save the file, which will have a .certSigningRequest extension. The corresponding private key is now stored in the login keychain. <strong>This private key is irreplaceable by Apple and you must store it yourself.</strong></p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748288861336/50f20da3-69d9-476d-97e7-331f9b9b5c76.png" alt="Dialog for the CSR creation" class="image--center mx-auto" width="684" height="510" loading="lazy"></p>
<h4 id="heading-how-to-generate-and-download-your-apple-certificates">How to Generate and Download Your Apple Certificates</h4>
<p>Once you’ve created a CSR, you can request a certificate from the Apple Developer Portal:</p>
<ol>
<li><p>Navigate to "Certificates, Identifiers &amp; Profiles" and select "Certificates".</p>
</li>
<li><p>Click the add button (+).</p>
</li>
<li><p>Choose the desired certificate type</p>
</li>
<li><p>Follow the prompts, and when asked, upload the .certSigningRequest file generated earlier.</p>
</li>
<li><p>After Apple processes the request, the certificate will be available for download as a .cer file.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748289386364/78f46b4e-b232-4484-98c2-dcb75120fd61.png" alt="Prompt to upload the CSR after selecting the type of certificate" class="image--center mx-auto" width="1293" height="319" loading="lazy"></p>
</li>
</ol>
<p>To install the certificate, double-click the downloaded .cer file. It will be added to the Keychain Access application – usually appearing in the "login" keychain under the "My Certificates" category, where it should be paired with the private key generated during the CSR generation process earlier.</p>
<p>You can see my certificate and private key in the image below for reference.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748289120657/38f711dd-887a-4fae-844d-e389c65234cf.png" alt="An example of how your certificate and the private key will look like in the keychain" class="image--center mx-auto" width="905" height="44" loading="lazy"></p>
<p>To recap, the CSR certifies that you generated the request from your mac. The certificate certifies that Apple (in this case, an intermediary like the "Apple Worldwide Developer Relations Certification Authority") confirms that they verified the CSR and that it is indeed you who will sign with the certificate (<code>.cer</code>) file.</p>
<p>This is enforced by only you having access to the private key – if you lose it, you cannot use this certificate anymore.</p>
<p>So, if you use this certificate (and the private key) to sign an app, the app store / operating system knows that it is you for sure since Apple confirmed it.</p>
<h3 id="heading-how-to-store-your-keys-what-are-p12-files">How to Store Your Keys: What are .p12 Files?</h3>
<p>As I mentioned in the previous section, to code sign an app you need your certificate (containing the public key) and the corresponding private key. This is created along with the CSR, and you can find it in the <code>Keychain Access</code> app.</p>
<p>We call the combination of the certificate and the private key a digital identity. This proves your identity when you sign an app with them.</p>
<h4 id="heading-p12-files-personal-information-exchange">.p12 Files (Personal Information Exchange):</h4>
<p>A .p12 file is a password-protected archive format used to bundle a certificate along with its private key. Its primary purposes are:</p>
<ul>
<li><p>Backing up the digital identity in case you lose access to your Mac.</p>
</li>
<li><p>Transferring the digital identity to another Mac (for example, for another team member or a new development machine).</p>
</li>
<li><p>Providing the identity to automated build systems or third-party build services.</p>
</li>
</ul>
<p>Historically, I have stored the .p12 file on a shared drive with my team and shared the password to it verbally – you can also store it in a local backup disk.</p>
<p>Great. So how do you create one?</p>
<h4 id="heading-to-export-a-p12-file-from-keychain-access">To export a .p12 file from Keychain Access:</h4>
<ol>
<li><p>Open Keychain Access, select the "login" keychain, and go to the "My Certificates" category.</p>
</li>
<li><p>Locate the desired certificate. It should have an expandable disclosure triangle indicating an associated private key (look at the image of my certificate above).</p>
</li>
<li><p>Select <em>both</em> the certificate and its private key (or right-click the certificate and choose "Export").</p>
</li>
<li><p>Right-click and choose "Export [X] items...".</p>
</li>
<li><p>In the save dialog, choose the "Personal Information Exchange (.p12)" file format.</p>
</li>
<li><p>Assign a strong password to protect the .p12 file. This password will be required when importing the file elsewhere. It is crucial for security.</p>
</li>
<li><p>Save the file to a secure location.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748297124625/f9d2cfe0-3538-405e-8fb0-af08276c4326.png" alt="Image of exporting my certificate and private key as a .p12 file" class="image--center mx-auto" width="468" height="266" loading="lazy"></p>
</li>
</ol>
<h2 id="heading-bridge-between-everything-provisioning-profiles"><strong>Bridge Between Everything: Provisioning Profiles</strong></h2>
<p>Provisioning profiles are the final link between an App ID, developer certificates, and, in some cases, a list of specific test devices. They act as a permission slip, authorizing an app signed with a particular certificate to be installed and run either on designated devices or to be submitted to the App Store.</p>
<h3 id="heading-what-exactly-is-a-provisioning-profile">What Exactly is a Provisioning Profile?</h3>
<p>A provisioning profile is a <code>.mobileprovision</code> (for iOS / VisionOS) or <code>.provisionprofile</code> (for macOS) file that holds several key pieces of information:</p>
<ul>
<li><p><strong>The App ID:</strong> Specifies which application (or set of applications, if using a wildcard App ID) the profile applies to.</p>
</li>
<li><p><strong>Certificates:</strong> Contains one or more developer or distribution certificates that can be used to sign the app.</p>
</li>
<li><p><strong>Device UDIDs (for Development and Ad Hoc):</strong> For profiles intended for testing on specific devices, it includes a list of the Unique Device Identifiers (UDIDs) of those authorized devices – more on devices in the next section.</p>
</li>
<li><p><strong>Entitlements:</strong> A list of app services or capabilities (like Push Notifications, iCloud, App Groups) that the app is permitted to use. These are derived from the capabilities enabled for the <em>associated App ID</em>.</p>
</li>
</ul>
<p>You can open the file using <code>vim</code> or any editor to see parts of the content which include the App Id, Operating Systems, Certificates, and so on.</p>
<p>The operating system checks the provisioning profile at app launch to ensure the app is authorized to run on the current device and use the requested services. If the profile is missing, invalid, or doesn't match the app's signature or the device, the app will not launch.</p>
<p>They are difference from certificates, because certificates are tied to you as a developer. But provisioning profiles are to a specific app – with specific capabilities to a specific developer and maybe on specific devices.</p>
<p>If any of these change (let’s say you added a capability or your certificate expired, for example), you’ll need to generate the provisioning profile again. These are the files you will work with the most out of all the above, and any change can cause your profile to become invalid.</p>
<h3 id="heading-types-of-provisioning-profiles-development-ad-hoc-app-store-and-enterprise">Types of Provisioning Profiles: Development, Ad Hoc, App Store, (and Enterprise)</h3>
<h3 id="heading-types-of-provisioning-profiles-development-ad-hoc-app-store-and-enterprise-1"><strong>Types of Provisioning Profiles: Development, Ad Hoc, App Store, (and Enterprise)</strong></h3>
<p>Just like certificates, we have multiple types of provisioning profiles. Similar to certificates, there can be development and distribution provisioning profiles.</p>
<p>Since we also keep track of the devices a profile is supposed to run, we have several kinds of distribution profiles based on which devices it should run on.</p>
<p>We also have special profiles like “Enterprise” which will add additional capabilities (like main camera access on the Vision Pro) but will restrict your app distribution methods to enterprise only.</p>
<p>We will go over each of these types now. Feel free to skip to the one that you’re looking for.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Profile Type</strong></td><td><strong>Purpose</strong></td><td><strong>Required Certificate Type(s)</strong></td><td><strong>Device Registration Required?</strong></td><td><strong>Distribution Method</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Development</strong></td><td>Install &amp; debug on registered devices during development (need Xcode to install).</td><td>Development</td><td>Yes</td><td>Xcode run, local device deployment.</td></tr>
<tr>
<td><strong>Ad Hoc</strong></td><td>Distribute to a limited number of registered test devices (no need for Xcode).</td><td>Distribution</td><td>Yes</td><td>Manual install (for example, via link, email, MDM) for testers.</td></tr>
<tr>
<td><strong>App Store Connect</strong></td><td>Submit app to App Store Connect for TestFlight or App Store release.</td><td>Distribution</td><td>No</td><td>Upload to App Store Connect.</td></tr>
<tr>
<td><strong>Enterprise</strong></td><td>Distribute proprietary apps to employees within an organization.</td><td>Enterprise (Distribution)</td><td>No (subject to program terms)</td><td>Internal distribution (e.g., private portal, MDM).</td></tr>
<tr>
<td><strong>Developer ID</strong></td><td>Allows a macOS app that is distributed outside the App Store to use advanced features</td><td>Developer ID</td><td>No</td><td>Outside the Mac App Store (for example, a web page, USB, MDM )</td></tr>
</tbody>
</table>
</div><h4 id="heading-development-provisioning-profile"><strong>Development Provisioning Profile:</strong></h4>
<ul>
<li><p><strong>Allows</strong> an app to be installed and debugged on specific devices registered in the developer's account during the active development phase. More on device registration later.</p>
</li>
<li><p><strong>Contains</strong> an App ID, one or more development certificates, and a list of registered device UDIDs.</p>
</li>
<li><p><strong>Created</strong> manually in the Apple Developer Portal or generated automatically by Xcode if <code>Automatically manage signing</code> is enabled.</p>
</li>
</ul>
<h4 id="heading-ad-hoc-provisioning-profile"><strong>Ad Hoc Provisioning Profile:</strong></h4>
<ul>
<li><p><strong>Allows</strong> distribution of an app to a limited number of registered test devices <strong>without</strong> requiring Xcode for installation. This is ideal for distributing builds to QA teams, beta testers, or clients for feedback.</p>
</li>
<li><p><strong>Contains</strong> an App ID (often an explicit App ID, or an Xcode-managed one like <code>XC Wildcard</code> or <code>XC</code>), a single distribution certificate, and a list of registered device UDIDs.</p>
</li>
<li><p><strong>Created</strong> manually in the Developer Portal or managed by Xcode's automatic signing.</p>
</li>
</ul>
<h4 id="heading-app-store-connect-provisioning-profile"><strong>App Store Connect Provisioning Profile:</strong></h4>
<ul>
<li><p><strong>Required</strong> to sign an app for submission to App Store Connect. This is the pathway for distributing apps via TestFlight for broader beta testing and for official release on the App Store.</p>
</li>
<li><p><strong>Contains</strong> an explicit App ID (or an App ID that matches the app's bundle ID, including Xcode-managed App IDs), and a single distribution certificate. <em>Device UDIDs are not included in this profile type since this is meant for broader distribution.</em></p>
</li>
<li><p><strong>Created</strong> manually in the Developer Portal or managed by Xcode's automatic signing.</p>
</li>
</ul>
<h4 id="heading-enterprise-provisioning-profile"><strong>Enterprise Provisioning Profile:</strong></h4>
<ul>
<li><p>Exclusively for members of the <strong>Apple Developer Enterprise Program</strong>. It allows developers of these orgs to distribute proprietary, in-house applications directly to their employees, bypassing the public App Store.</p>
</li>
<li><p>Note: This program has stringent enrollment criteria and is strictly for internal distribution within the enrolled organization – these apps cannot be pushed to AppStore.</p>
</li>
</ul>
<h4 id="heading-developer-id-provisioning-profile"><strong>Developer ID Provisioning Profile:</strong></h4>
<ul>
<li><p><strong>Required</strong> to utilize certain Apple services or advanced capabilities like Push Notifications, CloudKit, Sign in with Apple, or specific iCloud services.</p>
</li>
<li><p><strong>Contains</strong> an App ID, a Developer ID distribution certificate, the entitlements authorized for the app.</p>
</li>
<li><p><strong>Created</strong> manually in the Developer Portal – will not be added automatically by Xcode’s automatic signing.</p>
</li>
</ul>
<h3 id="heading-how-to-create-and-manage-provisioning-profiles">How to Create and Manage Provisioning Profiles</h3>
<p>Creating and managing provisioning profiles usually requires an Account Holder or Admin role in the Apple Developer Program. You also need a configured App ID, the appropriate certificate(s), and for Development or Ad Hoc profiles, a list of registered device UDIDs.</p>
<p>If you are new developer, my recommendation is to read this article completely, then get back to this section once you have your devices setup.</p>
<p>General steps for manual creation in the Developer Portal:</p>
<ol>
<li><p>Navigate to "Certificates, Identifiers &amp; Profiles" and select "Profiles".</p>
</li>
<li><p>Click the add button (+).</p>
</li>
<li><p>Select the type of provisioning profile to create (for example, "iOS App Development," "Ad Hoc," "App Store").</p>
</li>
<li><p>Choose the App ID you’re targeting from the dropdown list.</p>
</li>
<li><p>Select the certificate(s) to include in the profile. Development profiles can include multiple development certificates – so you can include all the team member certificates here. Ad Hoc and App Store profiles include a single distribution certificate.</p>
</li>
<li><p>If creating a Development or Ad Hoc profile, select the registered devices to include.</p>
</li>
<li><p>Provide a name for the provisioning profile (this is for identification in the portal and Xcode).</p>
</li>
<li><p>Click "Generate" and then "Download" the <code>.mobileprovision</code> or <code>.provisionprofile</code> file.</p>
</li>
</ol>
<p>You need to make downloaded profiles available to Xcode. You can often do this by double-clicking the downloaded file or by refreshing profiles within Xcode's account settings (Preferences &gt; Accounts).</p>
<p>I really like Xcode's "Automatically manage signing" feature and it can simplify profile management by a lot. It creates and updates profiles as needed. But, understanding the manual process is crucial for troubleshooting because when things go wrong, it is straightforward to debug the issue with this knowledge.</p>
<p>Provisioning profiles will become invalid and require regeneration if:</p>
<ul>
<li><p>The capabilities of the associated App ID are changed – let’s say you added a new capability.</p>
</li>
<li><p>An included certificate expires or is revoked.</p>
</li>
<li><p>For Development/Ad Hoc profiles, if devices are added or removed from the registered list in a way that affects the profile's device set, or if the profile's own expiration date is reached. When such changes occur, you have to edit the profile (if possible) or delete it and recreate it in the Developer Portal, then re-download it and install it again. While this may seem like a complicated step, it’s straightforward if you do it a couple of times.</p>
</li>
</ul>
<h2 id="heading-device-management-development-and-ad-hoc-builds"><strong>Device Management — Development and Ad Hoc Builds</strong></h2>
<p>For testing applications on physical Apple hardware outside of Testflight or AppStore, you’ll need to register the Unique Device Identifiers (UDIDs) of your test devices with your Apple Developer account. This registration is a necessary step for creating Development and Ad Hoc provisioning profiles.</p>
<h3 id="heading-why-you-need-to-register-test-devices">Why You Need to Register Test Devices</h3>
<p>Development and Ad Hoc provisioning profiles are specifically tied to a list of registered devices. An app signed with this profile can be installed directly without going through App Store process. This means that you need to register devices you intend to develop on. This restricts bad faith actors from releasing apps widely without developer and App Store supervision.</p>
<p>The UUID of a device is like a physical address (think Mac Address). If you don’t include this in the provisioning profile you used to sign an app package, it cannot be installed on that device.</p>
<p>Let’s go over the steps to do that.</p>
<h3 id="heading-how-to-find-your-devices-udid-unique-device-identifier">How to Find Your Device's UDID (Unique Device Identifier)</h3>
<p>A UDID is a unique 40-character hexadecimal string (for older devices) or a 25-character string (format XXXXXXXX-XXXXXXXXXXXXXXXX) that uniquely identifies a specific iPhone, iPad, Apple Watch, Apple TV, Vision Pro or Mac.</p>
<p>There are several ways to find a device's UDID:</p>
<ul>
<li><p><strong>Xcode:</strong> Connect the device to a Mac running Xcode. Open Xcode and navigate to Window &gt; Devices and Simulators. Select the connected device from the list on the left. The UDID will be displayed as the "Identifier" in the device information panel.</p>
</li>
<li><p><strong>Finder (macOS Catalina and later):</strong> Connect the iOS or iPadOS device to a Mac. Open Finder and select the device from the sidebar under "Locations." The UDID may be displayed directly, or it might be necessary to click on the line of text beneath the device's name (which shows model, storage, and OS version) to cycle through to display the UDID.</p>
</li>
<li><p><strong>iTunes (older macOS versions):</strong> For Macs running macOS Mojave or earlier, connect the device and open iTunes. Select the device icon when it appears. In the "Summary" tab, click on the "Serial Number" field; this will change to display the UDID.</p>
</li>
<li><p><strong>Apple Silicon Macs:</strong> When registering an Apple Silicon Mac, it's important to look for the "Provisioning UDID," which can be found in System Information under Hardware &gt; Provisioning UDID.</p>
</li>
<li><p><strong>Other Ways:</strong> There are some websites that will install a profile on to your device to get the UUID – so as an absolute last resort, you can do this. <em>But I highly recommend doing it in the one of the official ways to avoid any potential issues.</em></p>
</li>
</ul>
<h3 id="heading-how-to-register-devices-in-the-apple-developer-portal">How to Register Devices in the Apple Developer Portal</h3>
<p>Device registration is managed through the "Certificates, Identifiers &amp; Profiles" section of the Apple Developer Portal (developer.apple.com) and typically requires an Account Holder or Admin role.</p>
<p>To manually register a single device:</p>
<ol>
<li><p>Sign in to the Apple Developer Portal and navigate to "Certificates, Identifiers &amp; Profiles," then select "Devices" from the sidebar.</p>
</li>
<li><p>Click the add button (+) to register a new device.</p>
</li>
<li><p>Select the correct platform for the device (for example, iOS, macOS, tvOS, watchOS).</p>
</li>
<li><p>Enter a descriptive "Device Name" (this is for your reference, for example, "Sravan’s iPhone 11 Pro") and the device's UDID obtained in the previous step.</p>
</li>
<li><p>Click "Continue," review the information to make sure everything is correct, and then click "Register".</p>
</li>
</ol>
<p>For registering multiple devices, the portal supports uploading a specially formatted text file (a .txt or a .deviceids file) containing device names and UDIDs.</p>
<p>If "Automatically manage signing" is enabled in Xcode, Xcode can automatically register a connected device when it's selected as a build target. This is the way I managed all of my personal projects and devices. On the other hand, the file upload was really useful at my workplace to keep track of all the devices and add them at once.</p>
<h3 id="heading-understanding-device-limits-and-annual-resets">Understanding Device Limits and Annual Resets</h3>
<p>The Apple Developer Program imposes limits on the number of devices that can be registered for testing:</p>
<ul>
<li><p><strong>Annual Limit:</strong> Each membership year, a development team can register up to 100 devices for each product family (iPhone, iPad, Apple Watch, Apple TV, Apple Vision Pro, Mac). If you are a large team, this can potentially bottleneck you. When we ran into this issue, we created a new development team that could be split so that it didn’t have too much interdependence. There is no other way as far as I know, other than asking Apple and appealing them.</p>
</li>
<li><p><strong>Disabling Devices:</strong> While a device can be disabled in the portal during the membership year, doing so <strong>does not free up its slot or increase the number of available devices for that year</strong>. This part is frustrating but I think this is the only way they can enforce the 100 device limit to avoid people swapping devices. They should just provide a pathway to increase the limit, really. Disabling a device will, however, invalidate any provisioning profiles that include it, requiring those profiles to be regenerated.</p>
</li>
<li><p><strong>Resetting Device List (Start of New Membership Year):</strong> At the beginning of a new membership year, Account Holders, Admins, and App Managers are given a one-time option when they first sign in to "Certificates, Identifiers &amp; Profiles" to remove devices from their list. This allows them to "reset" their available device count back to 100 for each product family. You can choose to remove specific devices or all registered devices. <strong>This is your one chance per year to remove unused devices completely and free up slots for new devices.</strong></p>
</li>
<li><p><strong>Membership Expiration:</strong> If a developer program membership is nearing expiration and is not planned for renewal, the Account Holder will have an option, starting 30 days before expiration, to download a copy of their registered device list. They can also opt to have all devices removed from the account immediately upon membership expiration. If no action is taken, devices are typically removed automatically 180 days after membership expiration.</p>
</li>
</ul>
<h2 id="heading-possibilities-enabling-capabilities-and-services"><strong>Possibilities: Enabling Capabilities and Services</strong></h2>
<p>App Capabilities (or App Services) are features provided by Apple that we (as developers) can integrate into our applications to extend functionality and provide richer user experiences. Examples include iCloud storage, Push Notifications, Sign in with Apple, Apple Pay and HealthKit integration. Enabling these often requires explicit configuration for an app's App ID in the Apple Developer Portal and within the Xcode project.</p>
<h3 id="heading-why-you-should-use-capabilities">Why You Should Use Capabilities</h3>
<p>Making full use of these App capabilities can set your app apart from other apps in a very noticeable way. You can use Apple Wallet integration if you want users to scan a membership card. You can use journaling suggestions if you want to prompt them to journal something. You can use iCloud Storage to lean further into inter-device synchronization.</p>
<p>When you enable a capability for an App ID, it results in specific entitlements being added to the app's provisioning profile. These entitlements are permissions that the operating system checks at runtime to ensure the app is authorized to use the requested service.</p>
<h3 id="heading-how-to-configure-capabilities-for-your-app-id-apple-developer-portal">How to Configure Capabilities for Your App ID (Apple Developer Portal)</h3>
<p>Enabling and configuring capabilities is typically done by an Account Holder or Admin in the Apple Developer Portal (developer.apple.com).</p>
<ol>
<li><p>Navigate to "Certificates, Identifiers &amp; Profiles" and select "Identifiers."</p>
</li>
<li><p>Choose the App ID for which capabilities need to be configured.</p>
</li>
<li><p>In the App ID's settings, there will be a "Capabilities" tab. Select the checkboxes for the capabilities the app requires.</p>
</li>
<li><p>Many capabilities require additional configuration steps. For these, a "Configure" or "Edit" button will usually appear next to the capability once selected. Examples include:</p>
</li>
</ol>
<ul>
<li><p><strong>App Groups:</strong> Requires creating or selecting an app group identifier to allow data sharing between a main app and its extensions, or between different apps from the same developer.</p>
</li>
<li><p><strong>Apple Pay:</strong> Requires associating one or more Merchant IDs with the App ID.</p>
</li>
<li><p><strong>iCloud:</strong> May require choosing Xcode version compatibility and creating or assigning iCloud containers for Key-Value or Document storage</p>
</li>
<li><p><strong>Sign in with Apple:</strong> May require configuring the App ID as a primary app or grouping it with an existing primary App ID, and optionally providing a server-to-server notification endpoint URL.</p>
</li>
</ul>
<ol start="5">
<li>After configuring all selected capabilities, click "Save." A warning dialog may appear, which needs confirmation to finalize the changes.</li>
</ol>
<p><strong>Enabling a capability in the Developer Portal is only one part of the process.</strong> You’ll also need to add and configure it within the app's target in the Xcode project, under the "Signing &amp; Capabilities" tab.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748480139418/6a4007b3-01bd-484a-865c-8c5e728e15e0.png" alt="Showing the Signing &amp; Capabilities screen in Xcode" class="image--center mx-auto" width="614" height="114" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748480260906/e0dcec33-24ce-448b-91be-b79f5638e6fc.png" alt="Screenshot showing the Capabilities selector in Xcode" class="image--center mx-auto" width="793" height="608" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748480340624/ac56896a-0fb0-4cb0-a3fc-c894a255794a.png" alt="Screenshot of Xcode showing three capabilities. " class="image--center mx-auto" width="1187" height="434" loading="lazy"></p>
<ol>
<li><p>Navigate to the project settings and select “Signing &amp; Capabilities”.</p>
</li>
<li><p>Press the “+ Capability” button to select the capability.</p>
</li>
<li><p>Once selected, the capability should appear in the pane. Depending on the capability, you might want to configure it further.</p>
</li>
</ol>
<p>This Xcode step integrates the necessary frameworks, adds entitlements files to the project, and adjusts build settings.</p>
<h3 id="heading-how-enabling-capabilities-affects-your-provisioning-profiles">How Enabling Capabilities Affects Your Provisioning Profiles</h3>
<p>Changes to an App ID's enabled capabilities have a direct and significant impact on its associated provisioning profiles.</p>
<ul>
<li><p><strong>Invalidation:</strong> When a capability is enabled, disabled, or its configuration is modified for an App ID, <strong>all existing provisioning profiles that use that App ID immediately become invalid</strong>.</p>
</li>
<li><p><strong>Regeneration Required:</strong> These invalidated provisioning profiles must be regenerated (either by editing and re-saving them in the Developer Portal or by having Xcode's automatic signing handle it). The regenerated profiles will then include the updated set of entitlements corresponding to the newly configured capabilities.</p>
</li>
<li><p><strong>Platform Impact:</strong> Enabling a capability for an App ID that is used across multiple platforms (for example, an iOS app and its watchOS companion) will affect the provisioning profiles for all eligible platforms that use that App ID.</p>
</li>
</ul>
<p>This is something to keep in mind. Especially when it comes to distribution profiles since those are usually manually managed.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>While all of these might seem daunting, Apple’s automatic process should handle most of it. But I highly recommend learning how everything works so that you can debug it in case something goes wrong. I also highly recommend using manually created profiles for distribution.</p>
<p>While signing and handling certificates is not the most exciting part of the App development process, it is a necessary skill to have. In my next article, I will go over distributing an app from start to finish (which includes these processes and more restrictions).</p>
<p>You can follow me at <a class="user-mention" href="https://hashnode.com/@sravankaruturi">Sravan Karuturi</a> for my other posts.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Voice-Based Todo App using React, Firebase, and Alan AI ]]>
                </title>
                <description>
                    <![CDATA[ By Nishant Kumar React Todo applications are generally very basic – in fact, they're a great exercise if you're a React beginner and want to work on building up your skills. But have you ever built a Todo application where a user can add todos using ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-voice-based-weather-application-using-react-and-alan-ai/</link>
                <guid isPermaLink="false">66d4604ec7632f8bfbf1e45b</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Firebase ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 16 Nov 2021 15:32:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/11/How-to-Build-a-Weather-Application-using-React--36-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Nishant Kumar</p>
<p>React Todo applications are generally very basic – in fact, they're a great exercise if you're a React beginner and want to work on building up your skills.</p>
<p>But have you ever built a Todo application where a user can add todos using voice commands? This makes it a bit more complex and exciting.</p>
<p>So that's what we're going to do in this tutorial. And to build this voice-based Todo app, we will be using three main tools:</p>
<ol>
<li>React – for the user interface.</li>
<li>Firebase – for the database.</li>
<li>Alan AI – for implementing voice commands.</li>
</ol>
<p>So, let's get started.</p>
<h2 id="heading-how-to-create-the-todo-app-ui-using-react">How to Create the Todo App UI using React</h2>
<p>Let's create our React app first. Simply type in the following command:</p>
<pre><code>npx create-react-app react-todo-alan-firebase
</code></pre><p>It will initialize and create our React Application like this. Then, we'll navigate into that folder and start the application using npm start.</p>
<p>Now let's create a folder called components. It will contain our main component, called Todo.js. Create the Todo.js file as well.</p>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todo</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre><p>Give the application a header (or name), something like Voice-based Todo Application, or anything of your choice.</p>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todo</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Voice-based Todo Application<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre><p>Then, import this component into your App.js file.</p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;
<span class="hljs-keyword">import</span> Todo <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Todo'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Todo</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre><p>You will see the Header on the output screen.</p>
<p>Let's make the header appear in the center. So, give the <code>h2</code> a classname of header in the Todo.js component.</p>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todo</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span>Voice-based Todo Application<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre><p>And then we'll add some styling in App.css file so the header is centered.</p>
<pre><code>.header{
  text-align: center;
}
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-215217.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You will see the above output on the screen, with the centered header.</p>
<p>Now, let's create a card that will contain our todo items.</p>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todo</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-main"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span>Voice-based Todo Application<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-card"</span>&gt;</span>

            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre><p>Create a div and make the <code>className</code> be <code>todo-card</code>. You will see the main parent div has the <code>className</code> of <code>todo-main</code>. This is because we need everything in the center.</p>
<pre><code>.todo-main {
  <span class="hljs-attr">display</span>: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.header {
  text-align: center;
}

.todo-card {
  <span class="hljs-attr">border</span>: <span class="hljs-number">1</span>px dashed #<span class="hljs-number">1</span>f133d;
  height: <span class="hljs-number">50</span>vh;
  width: <span class="hljs-number">50</span>vh;
  border-radius: <span class="hljs-number">20</span>px;
}
</code></pre><p>And add the above styles to App.css. It'll look like this now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-220125.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Let's add the lists now. </p>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todo</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-main"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span>Voice-based Todo Application<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-card"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
                        Wash the Clothes
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
                        Cook the Dinner
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
                        Code some software
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre><p>So, I have created a div, and it contains the items in <code>h3</code> tags. These texts are static for now, but we will soon create dynamic texts too, coming from the Firebase Database.</p>
<p>And here are our updated styles:</p>
<pre><code>.todo-main {
  <span class="hljs-attr">display</span>: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.header {
  text-align: center;
}

.todo-card {
  <span class="hljs-attr">border</span>: <span class="hljs-number">1</span>px dashed #<span class="hljs-number">1</span>f133d;
  height: <span class="hljs-number">50</span>vh;
  width: <span class="hljs-number">50</span>vh;
  border-radius: <span class="hljs-number">20</span>px;
}

.todo-list{
  text-align: center;
}
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-220710.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>So that's the output now, with three items on our list.</p>
<p>Now, let's add a close icon, that will remove each item after we are done with it.</p>
<p>And to add icons, we need an icon package. So, let's install React Icons with this command:</p>
<pre><code>npm install react-icons --save
</code></pre><p>After the installation, choose any icon package from the left sidebar.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-220805.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>I am using Feather Icons, so I will import it.</p>
<p>First, let's import that package using this command:</p>
<pre><code><span class="hljs-keyword">import</span> { FiX } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/fi"</span>;
</code></pre><p>Then, call it after the h3 tag.</p>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { FiX } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/fi"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todo</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-main"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span>Voice-based Todo Application<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-card"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
                        Wash the Clothes
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">FiX</span> /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
                        Cook the Dinner
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">FiX</span> /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
                        Code some software
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">FiX</span> /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-221145.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Above, this is what our application looks like now. But we want the close icon and the todo item to be in the same row.</p>
<p>Give the Icon a className of <code>close-icon</code>.</p>
<pre><code> &lt;FiX className=<span class="hljs-string">"close-icon"</span> /&gt;
</code></pre><p>And in the App.css, add the following styles:</p>
<pre><code>.todo-list {
  <span class="hljs-attr">display</span>: flex;
  align-items: center;
  justify-content: center;
}

.close-icon {
  margin-left: <span class="hljs-number">10</span>px;
}
</code></pre><p>Our Todo.js component will have the following final code up to this point:</p>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { FiX } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/fi"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todo</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-main"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span>Voice-based Todo Application<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-card"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
                        Wash the Clothes
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">FiX</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"close-icon"</span> /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
                        Cook the Dinner
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">FiX</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"close-icon"</span> /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
                        Code some software
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">FiX</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"close-icon"</span> /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre><p>And our App.css looks like this:</p>
<pre><code>.todo-main {
  <span class="hljs-attr">display</span>: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.header {
  text-align: center;
}

.todo-card {
  <span class="hljs-attr">border</span>: <span class="hljs-number">1</span>px dashed #<span class="hljs-number">1</span>f133d;
  height: <span class="hljs-number">50</span>vh;
  width: <span class="hljs-number">50</span>vh;
  border-radius: <span class="hljs-number">20</span>px;
}

.todo-list {
  <span class="hljs-attr">display</span>: flex;
  align-items: center;
  justify-content: center;
}

.close-icon {
  margin-left: <span class="hljs-number">10</span>px;
}
</code></pre><p>Now this is how our UI will look:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-221826.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-add-alan-ai-to-our-react-project">How to Add Alan AI to our React Project</h2>
<p>Head over to <a target="_blank" href="https://alan.app/">https://alan.app/</a> and create your account.</p>
<p>After signing in, you can create a project. Just click the plus button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-222106.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>But before we can use it, we need to install the Alan AI package first. So, head over to <a target="_blank" href="https://alan.app/docs/client-api/web/react">https://alan.app/docs/client-api/web/react</a> for the React documentation.</p>
<p>Install Alan Al using the following command:</p>
<pre><code>npm install @alan-ai/alan-sdk-web --save
</code></pre><p>Now, let's import Alan in our main App.js file.</p>
<pre><code><span class="hljs-keyword">import</span> alanBtn <span class="hljs-keyword">from</span> <span class="hljs-string">"@alan-ai/alan-sdk-web"</span>;
</code></pre><p>Then, we need to create a useEffect Hook. It will start our Alan service whenever our component is mounted or loaded.</p>
<pre><code>useEffect(<span class="hljs-function">() =&gt;</span> {
    alanBtn({
        <span class="hljs-attr">key</span>: <span class="hljs-string">'YOUR_KEY_FROM_ALAN_STUDIO_HERE'</span>,
        <span class="hljs-attr">onCommand</span>: <span class="hljs-function">(<span class="hljs-params">commandData</span>) =&gt;</span> {
            <span class="hljs-keyword">if</span> (commandData.command === <span class="hljs-string">'go:back'</span>) {
                <span class="hljs-comment">// Call the client code that will react to the received command</span>
            }
        }
    });
}, []);
</code></pre><p>This <code>alanBtn</code> requires a key which we'll need to get. So, in the project that you created in Alan, you should see an "Integrations" button in the top bar. Click that button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-222645.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And there you will get your key.</p>
<p>Paste that key in your <code>alanBtn</code> in your React app, like this:</p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;
<span class="hljs-keyword">import</span> Todo <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Todo'</span>;
<span class="hljs-keyword">import</span> alanBtn <span class="hljs-keyword">from</span> <span class="hljs-string">"@alan-ai/alan-sdk-web"</span>;
<span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  useEffect(<span class="hljs-function">() =&gt;</span> {
    alanBtn({
      <span class="hljs-attr">key</span>: <span class="hljs-string">'86e866fbe49666abd385ee5c9f9cbf5c2e956eca572e1d8b807a3e2338fdd0dc/stage'</span>,
      <span class="hljs-attr">onCommand</span>: <span class="hljs-function">(<span class="hljs-params">commandData</span>) =&gt;</span> {

      }
    });
  }, []);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Todo</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre><p>Now, check the output, and you will see a microphone button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-222913.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, we need to create an Intent in our Alan App. It will start with the Add command, like add Washing Clothes, add Write Some Code, and so on. So, let's write the code for that:</p>
<pre><code>intent(<span class="hljs-string">'Add $(item* (.*))'</span>, <span class="hljs-function">(<span class="hljs-params">p</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span>(p.item.value){
        p.play({ <span class="hljs-attr">command</span>: <span class="hljs-string">'todoApp'</span>, <span class="hljs-attr">data</span>: p.item.value });
        p.play(<span class="hljs-string">`<span class="hljs-subst">${p.item.value}</span> added`</span>);
    }
    <span class="hljs-keyword">else</span>{
        p.play(<span class="hljs-string">`Cannot add Empty Item`</span>);
    }
})
</code></pre><p>It will also return the item back to us, which we can see in our React Application. Here, we also have a check that stops us from adding any empty item. If we try, it will reply with "Cannot add Empty Item".</p>
<p>Now, we want to receive the spoken item back to our React application. </p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;
<span class="hljs-keyword">import</span> Todo <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Todo'</span>;
<span class="hljs-keyword">import</span> alanBtn <span class="hljs-keyword">from</span> <span class="hljs-string">"@alan-ai/alan-sdk-web"</span>;
<span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  useEffect(<span class="hljs-function">() =&gt;</span> {
    alanBtn({
      <span class="hljs-attr">key</span>: <span class="hljs-string">'86e866fbe49666abd385ee5c9f9cbf5c2e956eca572e1d8b807a3e2338fdd0dc/stage'</span>,
      <span class="hljs-attr">onCommand</span>: <span class="hljs-function">(<span class="hljs-params">commandData</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(commandData)
      }
    });
  }, []);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Todo</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre><p>Simply console.log the commandData, and you'll get the following result. Don't forget to click the microphone button and say something. You'll see what you said in the console.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-223428.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Alright great, our Alan AI is now all set.</p>
<h2 id="heading-how-to-use-firebase-to-send-data-to-the-firestore-database">How to Use Firebase to Send Data to the Firestore Database.</h2>
<p>We will now send this data to Firebase.</p>
<p>But first, we need to install it. Head over to <a target="_blank" href="https://firebase.google.com/">https://firebase.google.com/</a> and create a project there as well.</p>
<p>To install Firebase, simply type <code>npm install firebase</code>.</p>
<p>Then, create an application in the project, like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-223909.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>It will give us some configuration data. Just create a file in the src folder, name it <code>firebase-config.js</code>, and add those configuration data.</p>
<pre><code><span class="hljs-comment">// Import the functions you need from the SDKs you need</span>
<span class="hljs-keyword">import</span> { initializeApp } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/app"</span>;

<span class="hljs-comment">// Your web app's Firebase configuration</span>
<span class="hljs-keyword">const</span> firebaseConfig = {
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"AIzaSyCP8qL8z9BorGF3NZJsGb4vSaWHYyCVfc8"</span>,
    <span class="hljs-attr">authDomain</span>: <span class="hljs-string">"todo-firebase-alan.firebaseapp.com"</span>,
    <span class="hljs-attr">projectId</span>: <span class="hljs-string">"todo-firebase-alan"</span>,
    <span class="hljs-attr">storageBucket</span>: <span class="hljs-string">"todo-firebase-alan.appspot.com"</span>,
    <span class="hljs-attr">messagingSenderId</span>: <span class="hljs-string">"892581913000"</span>,
    <span class="hljs-attr">appId</span>: <span class="hljs-string">"1:892581913000:web:dbe08ac753c3adaab87d9d"</span>
};

<span class="hljs-comment">// Initialize Firebase</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> app = initializeApp(firebaseConfig);
</code></pre><p>Don't forget to export the const app.</p>
<p>Next, we need to access Firestore as well. So, let's import it here in our firebase-config.js file.</p>
<pre><code><span class="hljs-keyword">import</span> { getFirestore } <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase/firestore'</span>
</code></pre><pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> database = getFirestore(app);
</code></pre><p>And export it too at the bottom.</p>
<pre><code><span class="hljs-comment">// Import the functions you need from the SDKs you need</span>
<span class="hljs-keyword">import</span> { initializeApp } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/app"</span>;
<span class="hljs-keyword">import</span> { getFirestore } <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase/firestore'</span>

<span class="hljs-comment">// Your web app's Firebase configuration</span>
<span class="hljs-keyword">const</span> firebaseConfig = {
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"AIzaSyCP8qL8z9BorGF3NZJsGb4vSaWHYyCVfc8"</span>,
    <span class="hljs-attr">authDomain</span>: <span class="hljs-string">"todo-firebase-alan.firebaseapp.com"</span>,
    <span class="hljs-attr">projectId</span>: <span class="hljs-string">"todo-firebase-alan"</span>,
    <span class="hljs-attr">storageBucket</span>: <span class="hljs-string">"todo-firebase-alan.appspot.com"</span>,
    <span class="hljs-attr">messagingSenderId</span>: <span class="hljs-string">"892581913000"</span>,
    <span class="hljs-attr">appId</span>: <span class="hljs-string">"1:892581913000:web:dbe08ac753c3adaab87d9d"</span>
};

<span class="hljs-comment">// Initialize Firebase</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> app = initializeApp(firebaseConfig);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> database = getFirestore(app);
</code></pre><p>This is the whole firebase-config code.</p>
<p>Now, in App.js, we need to import this app and database.</p>
<pre><code><span class="hljs-keyword">import</span> { app, database } <span class="hljs-keyword">from</span> <span class="hljs-string">'./firebase-config'</span>;
</code></pre><p>Next, we need to create a connection to our Firebase Firestore. For that, we need the collection property from Firebase Firestore. Also, we'll import addDoc which we'll use to add data to Firestore.</p>
<pre><code><span class="hljs-keyword">import</span> { collection, addDoc } <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase/firestore'</span>;
</code></pre><p>Now, let's create the connection to our database.</p>
<p>Create a variable, and put in the database that we imported from the firebase-config file along with the name we want to give to our collection. Since we want the collection to be todo-list, we can add the following:</p>
<pre><code><span class="hljs-keyword">const</span> databaseRef = collection(database, <span class="hljs-string">'todo-list'</span>);
</code></pre><p>To add data, we need that addDoc property.</p>
<p>The addDoc property will take two parameters. The first is the connection we created, the databaseRef. The second is the data we want to add, as an object.</p>
<p>Put the addDoc in the useEffect Hook like this:</p>
<pre><code>useEffect(<span class="hljs-function">() =&gt;</span> {
    alanBtn({
      <span class="hljs-attr">key</span>: <span class="hljs-string">'86e866fbe49666abd385ee5c9f9cbf5c2e956eca572e1d8b807a3e2338fdd0dc/stage'</span>,
      <span class="hljs-attr">onCommand</span>: <span class="hljs-function">(<span class="hljs-params">commandData</span>) =&gt;</span> {
        addDoc(databaseRef, { <span class="hljs-attr">item</span>: commandData.data })
      }
    });
  }, []);
</code></pre><p>Currently, our Firestore is empty.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-225805.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, let's try this out. Speak something into the microphone starting with add command, and it will be visible in the Firebase Firestore.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-225922.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You see, what we said is now getting added in Firebase.</p>
<p>Now, let's try to read and display this data.</p>
<p>Pass the <code>databaseRef</code> to the Todo Component as a prop.</p>
<pre><code>&lt;Todo databaseRef={databaseRef}/&gt;
</code></pre><p>And then receive it in the Todo Component.</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todo</span>(<span class="hljs-params">{databaseRef}</span>)</span>
</code></pre><p>Create a useEffect hook in the Todo.js component, and inside the useEffect Hook create the function <code>getData</code>.</p>
<pre><code>useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> getData = <span class="hljs-keyword">async</span> () =&gt; {

        }
        getData()
    }, [])
</code></pre><p>We will use getDocs property to read data from the Firebase Firestore. And we also need that connection databaseRef, that we passed as a prop previously.</p>
<pre><code><span class="hljs-keyword">let</span> data = <span class="hljs-keyword">await</span> getDocs(databaseRef);
</code></pre><pre><code><span class="hljs-keyword">const</span> getData = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">let</span> data = <span class="hljs-keyword">await</span> getDocs(databaseRef);
  <span class="hljs-built_in">console</span>.log(data.docs.map(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> ({ ...item.data(), <span class="hljs-attr">id</span>: item.id })));
}
</code></pre><p>We map the incoming data to make it more readable. We also add the unique id of the item that the app will use to delete that item later.</p>
<p>Let's check our console now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-231500.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You see, we are getting it.</p>
<p>Now, let's store this data in a state to display in the React Application.</p>
<p>Import the useState Hook, then create an array state like this:</p>
<pre><code> <span class="hljs-keyword">const</span> [todoList, setTodoList] = useState([]);
</code></pre><p>And set the data using the <code>setTodoList</code> function:</p>
<pre><code>setTodoList(data.docs.map(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> ({ ...item.data(), <span class="hljs-attr">id</span>: item.id })));
</code></pre><p>Now, let's map the todoList array.</p>
<pre><code>&lt;div className=<span class="hljs-string">"todo-main"</span>&gt;
            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span>Voice-based Todo Application<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span></span>

            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-card"</span>&gt;</span>
                {todoList.map((todo) =&gt; {
                    return (
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
                                {todo.item}
                            <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">FiX</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"close-icon"</span> /&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    )
                })}
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
        &lt;/div&gt;
</code></pre><p>We will see our data in our React UI and it looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-231945.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, let's update this so that each Todo starts with a capital letter.</p>
<p>Give h3 as the <code>className</code> of <code>todo-items</code>.</p>
<pre><code>&lt;h3 className=<span class="hljs-string">"todo-item"</span>&gt;
 {todo.item}
&lt;/h3&gt;
</code></pre><p>And in App.css, add this styling:</p>
<pre><code>.todo-item{
  text-transform: capitalize;
}
</code></pre><p>And you will see that each Todo is capitalized now.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-232149.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, if we add anything by speech command, our list in React should update. So, let's configure our useEffect to run every time we speak something into the app.</p>
<p>In the App.js file, create one state. It will be a boolean, with the initial state of false.</p>
<pre><code><span class="hljs-keyword">const</span> [update, setUpdate] = useState(<span class="hljs-literal">false</span>)
</code></pre><p>This state will change to true when we say something, or when the useEffect in App.js runs.</p>
<pre><code>useEffect(<span class="hljs-function">() =&gt;</span> {
    alanBtn({
      <span class="hljs-attr">key</span>: <span class="hljs-string">'86e866fbe49666abd385ee5c9f9cbf5c2e956eca572e1d8b807a3e2338fdd0dc/stage'</span>,
      <span class="hljs-attr">onCommand</span>: <span class="hljs-function">(<span class="hljs-params">commandData</span>) =&gt;</span> {
        addDoc(databaseRef, { <span class="hljs-attr">item</span>: commandData.data })
        .then(<span class="hljs-function">() =&gt;</span> {
          setUpdate(<span class="hljs-literal">true</span>);
        })
      }
    });
  }, []);
</code></pre><p>Then, we will pass the update state and the function to update state in Todo.js. </p>
<pre><code>&lt;Todo databaseRef={databaseRef} update={update} setUpdate={setUpdate}/&gt;
</code></pre><p>And receive these two in the Todo component.</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todo</span>(<span class="hljs-params">{ databaseRef, update, setUpdate }</span>)</span>
</code></pre><p>Then, in the useEffect of Todo.js, once it's fetched our data from Firebase Firestore, set the update to false using the setUpdate function. Then put the update state in the dependency array. </p>
<pre><code>useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> getData = <span class="hljs-keyword">async</span> () =&gt; {
            <span class="hljs-keyword">let</span> data = <span class="hljs-keyword">await</span> getDocs(databaseRef);
            setTodoList(data.docs.map(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> ({ ...item.data(), <span class="hljs-attr">id</span>: item.id })));
        }
        getData()
        setUpdate(<span class="hljs-literal">false</span>)
    }, [update])
</code></pre><p>This might be a bit confusing, but let me explain.</p>
<p>When we speak, the update state is changed from false to true. Then, when the data fetching from Firestore is done, it is being changed to false from true. That way, the state is constantly changing. So the useEffect gets updated every time the update state changes.</p>
<p>Let's try it out now. Say something and the list will be dynamically updated.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-233617.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, let's add the delete function to delete items from Firebase Firestore and our React application.</p>
<p>Create a function called <code>deleteItems</code>.</p>
<pre><code><span class="hljs-keyword">const</span> deleteItems = <span class="hljs-function">() =&gt;</span> {

}
</code></pre><p>And bind this function to the <code>close</code> icon like this:</p>
<pre><code>&lt;FiX className=<span class="hljs-string">"close-icon"</span> onClick={<span class="hljs-function">() =&gt;</span> deleteItems()}/&gt;
</code></pre><p>When we click a particular close icon, we need to pass the id of that item to the function, which will be used to delete that item.</p>
<pre><code>&lt;FiX className=<span class="hljs-string">"close-icon"</span> onClick={<span class="hljs-function">() =&gt;</span> deleteItems(todo.id)}/&gt;
</code></pre><p>And in the function, receive it.</p>
<p>Let's try to console.log our id:</p>
<pre><code><span class="hljs-keyword">const</span> deleteItems = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(id)
}
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-15-234631.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We will get that particular id in the console.</p>
<p>Now, before deleting any todo item, we need to specify which todo to delete. So, we will create a reference using this id. We will use the doc property from Firestore.</p>
<p>So, first import doc from Firestore with this command:</p>
<pre><code><span class="hljs-keyword">import</span> { getDocs, doc } <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase/firestore'</span>;
</code></pre><p>Then, in the function 1deleteItems1, add the following code:</p>
<pre><code><span class="hljs-keyword">const</span> data = doc(database, <span class="hljs-string">'todo-list'</span>, id)
</code></pre><p>This doc takes three parameters – the database, the collection name, and the id. We have all the three things.</p>
<p>The database has been imported from firebase-config. The todo-list is the name of the Firestore collection. And the id we got from the close button click.</p>
<p>To delete an item, we need another property called deleteDoc from Firestore.</p>
<pre><code><span class="hljs-keyword">import</span> { getDocs, doc, deleteDoc } <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase/firestore'</span>;
</code></pre><p>Then, simply add the following:</p>
<pre><code><span class="hljs-keyword">const</span> deleteItems = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {
   <span class="hljs-keyword">const</span> data = doc(database, <span class="hljs-string">'todo-list'</span>, id);
   deleteDoc(data)
}
</code></pre><p>Try it now – click the close icon, then check Firestore. That item will be deleted.</p>
<p>But we have the same problem we had during the add and read actions: the React application is not getting updated after we delete an item.</p>
<p>So, the first thing to do is move the getData function outside the useEffect Hook. Don't worry, it will still work.</p>
<pre><code><span class="hljs-keyword">const</span> getData = <span class="hljs-keyword">async</span> () =&gt; {
   <span class="hljs-keyword">let</span> data = <span class="hljs-keyword">await</span> getDocs(databaseRef);
   setTodoList(data.docs.map(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> ({ ...item.data(), <span class="hljs-attr">id</span>: item.id })));
}

useEffect(<span class="hljs-function">() =&gt;</span> {   
   getData()
   setUpdate(<span class="hljs-literal">false</span>)
}, [update])
</code></pre><p>And in the deleteDoc function, we need to call the getData function again, to fetch the updated data after the user deletes an item.</p>
<pre><code><span class="hljs-keyword">const</span> deleteItems = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> data = doc(database, <span class="hljs-string">'todo-list'</span>, id);
    deleteDoc(data)
    .then(<span class="hljs-function">() =&gt;</span> {
       getData()
    })
}
</code></pre><p>Here is the whole Todo.js code:</p>
<pre><code><span class="hljs-keyword">import</span> React, { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { FiX } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/fi"</span>;
<span class="hljs-keyword">import</span> { database } <span class="hljs-keyword">from</span> <span class="hljs-string">'../firebase-config'</span>;
<span class="hljs-keyword">import</span> { getDocs, doc, deleteDoc } <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase/firestore'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todo</span>(<span class="hljs-params">{ databaseRef, update, setUpdate }</span>) </span>{
    <span class="hljs-keyword">const</span> [todoList, setTodoList] = useState([]);
    <span class="hljs-keyword">const</span> getData = <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">let</span> data = <span class="hljs-keyword">await</span> getDocs(databaseRef);
        setTodoList(data.docs.map(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> ({ ...item.data(), <span class="hljs-attr">id</span>: item.id })));
    }
    useEffect(<span class="hljs-function">() =&gt;</span> {
        getData()
        setUpdate(<span class="hljs-literal">false</span>)
    }, [update])

    <span class="hljs-keyword">const</span> deleteItems = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> data = doc(database, <span class="hljs-string">'todo-list'</span>, id);
        deleteDoc(data)
            .then(<span class="hljs-function">() =&gt;</span> {
                getData()
            })
    }

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-main"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span>Voice-based Todo Application<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-card"</span>&gt;</span>
                {todoList.map((todo) =&gt; {
                    return (
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-item"</span>&gt;</span>
                                {todo.item}
                            <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">FiX</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"close-icon"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> deleteItems(todo.id)} /&gt;
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    )
                })}
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre><p>And the App.js code as well:</p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;
<span class="hljs-keyword">import</span> Todo <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Todo'</span>;
<span class="hljs-keyword">import</span> alanBtn <span class="hljs-keyword">from</span> <span class="hljs-string">"@alan-ai/alan-sdk-web"</span>;
<span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { app, database } <span class="hljs-keyword">from</span> <span class="hljs-string">'./firebase-config'</span>;
<span class="hljs-keyword">import</span> { addDoc, collection } <span class="hljs-keyword">from</span> <span class="hljs-string">'@firebase/firestore'</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> databaseRef = collection(database, <span class="hljs-string">'todo-list'</span>);
  <span class="hljs-keyword">const</span> [update, setUpdate] = useState(<span class="hljs-literal">false</span>)
  useEffect(<span class="hljs-function">() =&gt;</span> {
    alanBtn({
      <span class="hljs-attr">key</span>: <span class="hljs-string">'86e866fbe49666abd385ee5c9f9cbf5c2e956eca572e1d8b807a3e2338fdd0dc/stage'</span>,
      <span class="hljs-attr">onCommand</span>: <span class="hljs-function">(<span class="hljs-params">commandData</span>) =&gt;</span> {
        addDoc(databaseRef, { <span class="hljs-attr">item</span>: commandData.data })
          .then(<span class="hljs-function">() =&gt;</span> {
            setUpdate(<span class="hljs-literal">true</span>);
          })
      }
    });
  }, []);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Todo</span> <span class="hljs-attr">databaseRef</span>=<span class="hljs-string">{databaseRef}</span> <span class="hljs-attr">update</span>=<span class="hljs-string">{update}</span> <span class="hljs-attr">setUpdate</span>=<span class="hljs-string">{setUpdate}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre><p>Now, we can add items using voice commands, and it will be stored in our Firebase Database. It will also show up in our React Application.</p>
<p>Ther's one last thing to do. In our App.css file, we need to set the height of the card to auto, to prevent the text from overflowing.</p>
<pre><code>.todo-card {
  <span class="hljs-attr">border</span>: <span class="hljs-number">1</span>px dashed #<span class="hljs-number">1</span>f133d;
  height: auto;
  width: <span class="hljs-number">50</span>vh;
  border-radius: <span class="hljs-number">20</span>px;
}
</code></pre><p>And this is just a simple UI design. You can use your own designs if you want. Go ahead, build this awesome application.</p>
<p>Thanks for reading!</p>
<p>You can check out my video on the same topic at <a target="_blank" href="https://youtu.be/BzHbI2AAXGs">Let's build a Voice-Based Todo Application using React, Firebase, and Alan AI</a>, which is on my YouTube channel.</p>
<blockquote>
<p>Happy Learning.</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn the JavaScript You Need to Build Apps in this 28-Part Course ]]>
                </title>
                <description>
                    <![CDATA[ Are you struggling to figure out what JavaScript skills you need to build real-world apps? Check out this concise, example-filled course that provides the core JavaScript concepts you need to be productive with libraries like React, Angular, and Vue.... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-javascript-to-build-apps/</link>
                <guid isPermaLink="false">66d037a4871ae63f179f6bb5</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ build apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ES6 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ online courses ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Reed ]]>
                </dc:creator>
                <pubDate>Tue, 14 Jul 2020 13:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/07/JavaScript-You-Need-To-Know.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Are you struggling to figure out what JavaScript skills you need to build real-world apps? <a target="_blank" href="https://bit.ly/2020-js-bootcamp">Check out this concise, example-filled course</a> that provides the core JavaScript concepts you need to be productive with libraries like React, Angular, and Vue.</p>
<p>If you want to build serious web applications, <strong>the language to use is JavaScript</strong>. </p>
<p>But what JavaScript skills do you need to build apps effectively?</p>
<h2 id="heading-what-are-the-essential-javascript-skills">What Are the Essential JavaScript Skills?</h2>
<p>There are tons of courses on JavaScript available find online, but few specialize in what so many developers want to know:</p>
<p><em>What JavaScript skills are essential to building your own applications?</em></p>
<p>There is a gap between learning vanilla JavaScript and learning a library like React, Angular, and Vue for creating single-page JavaScript applications. </p>
<p>I've put together a complete course with the goal of showing you how to bridge this gap.</p>
<p>My goal is not only to teach you the skills you need while presenting real-world examples to solidify your understanding, but also to give you a new perspective. You'll find a better way of looking at your JavaScript code that will help you start thinking like a professional app developer.</p>
<p><em>Want to get started now?</em> <a target="_blank" href="https://bit.ly/2020-js-bootcamp">Take the entire course here</a>.</p>
<h2 id="heading-course-overview">Course Overview</h2>
<p>Let's take a brief tour through the course and each major section. We'll see how each section will ensure that you're taught JavaScript in the most effective, no-nonsense way possible. </p>
<p>In this course, we'll develop our skills from basic concepts to more complex ones. Even if you're an intermediate JavaScript developer, we'll cover every concept with additional depth and observations on the language that you likely haven't heard before. </p>
<h3 id="heading-variables-and-strings">Variables and Strings</h3>
<p>We'll begin with the building blocks of any JS program: variables. </p>
<p>First we'll cover declaring variables with let and const and how they are an improvement over the old var syntax. We'll learn concepts like block scoping, variable shadowing and the temporal dead zone, but also discover how these new keywords can make our code easier to process. </p>
<p>For example, why the <code>salePrice</code> variable below becomes more readable when we declare it with const instead of let or var.</p>
<p><a target="_blank" href="https://courses.reedbarger.com/courses/2020-js-bootcamp/lectures/17117784"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nr3lU2vl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-3.cloudinary.com/hl8x9mfjy/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2020-07-13-at-7.47.42-PM.png" alt="Click to access the course" width="600" height="400" loading="lazy"></a> <em>Click to watch this lecture</em></p>
<p>Because we declare the variable with as a constant, we know that it won't be assigned a different value later on. This makes our code easier to understand both for other developers and for ourselves. </p>
<p>Finally, in this section we'll touch on template literals, and how they improve strings within JavaScript in basically every way, from formatting text, to inserting dynamic values, and more.</p>
<h3 id="heading-types-and-conditionals">Types and Conditionals</h3>
<p>Next we'll touch on types and conditionals, which go hand in hand. </p>
<p>We'll first take a look at a strange (and often poorly understood) part of JavaScript called type coercion, which means how types are changed from one value to another.</p>
<p>Types can change implicitly when we write conditionals and this means we must know about truthy and falsy values, values that are subtly coerced to the boolean true and falsy, respectively. </p>
<p>We'll see how we can use truthy and falsy values to our advantage by creating shorter conditionals using the &amp;&amp; (and) and || (or) operators. This trick, known as short circuiting, is the basis of how JS libraries like React display or hide elements. </p>
<p><a target="_blank" href="https://learn.codeartistry.io/courses/2020-js-bootcamp/lectures/17117805"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D7iXfT1y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-2.cloudinary.com/hl8x9mfjy/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2020-07-13-at-7.58.41-PM.png" alt="Click to access the course" width="600" height="400" loading="lazy"></a><em>Click to watch this lecture</em></p>
<p>Then we'll see how to shorten our if-else conditionals with the ternary operator, and how they come in handy in situations when we want to conditionally set a variable's value.</p>
<h3 id="heading-functions">Functions</h3>
<p>After that, we'll dive into functions, the powerhouse of any Javascript app.</p>
<p>We'll demystify a crucial feature of functions called closures. We'll wrap our head around what a closure is by through creating our in a practical example. </p>
<p>This will enable us to see why closures are worth knowing and how they can improve our JavaScript code by keeping track of values between function calls: </p>
<p><a target="_blank" href="https://learn.codeartistry.io/courses/2020-js-bootcamp/lectures/17117780"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kAkgK88W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-1.cloudinary.com/hl8x9mfjy/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2020-07-13-at-8.05.34-PM.png" alt="Click to access the course" width="600" height="400" loading="lazy"></a>
<em>Click to watch this lecture</em></p>
<p>We'll cover a type of function, which you'll find in every modern Javascript app, namely, arrow functions. With arrow functions, we can greatly cut down our code as we go through all of the available tricks to making them as concise as possible. </p>
<p>Lastly, we'll touch on default values in functions and how they can make our code more reliable, especially if an expected argument isn't provided.</p>
<h3 id="heading-objects">Objects</h3>
<p>From primitive data types, we'll move onto objects. </p>
<p>Understanding essential app-building concepts like mutations and immutability isn't possible without knowing the difference between primitive types and object types in JavaScript. We'll cover this difference in detail and see firsthand why it matters for the reliability of our code. </p>
<p>We'll touch on a variety of practical patterns to more easily get our object data through object destructuring, as you see below:</p>
<p><a target="_blank" href="https://learn.codeartistry.io/courses/2020-js-bootcamp/lectures/17117800"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WHgMYnlN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-2.cloudinary.com/hl8x9mfjy/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2020-07-13-at-11.16.13-PM.png" alt="Click to access the course" width="600" height="400" loading="lazy"></a>
<em>Click to watch this lecture</em></p>
<p>Then after destructuring our objects, we'll see how to better assemble them. By using the object spread operator we can seamlessly merge multiple objects in an immutable fashion.</p>
<h3 id="heading-arrays">Arrays</h3>
<p>Arrays are essential for any list of data that we display in our apps and we need to know how to manipulate them with ease.</p>
<p>We'll cover how to perform actions on all elements in arrays through higher order array functions like map and filter to transform our elements or remove them from our array. </p>
<p>Additionally, we'll use methods like find to get individual elements based on certain conditions:</p>
<p><a target="_blank" href="https://learn.codeartistry.io/courses/2020-js-bootcamp/lectures/17117785"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XsKHfHhi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-3.cloudinary.com/hl8x9mfjy/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2020-07-13-at-11.25.18-PM.png" alt="Click to access the course" width="600" height="400" loading="lazy"></a>
<em>Click to watch this lecture</em></p>
<p>Then we'll cover the most important array method, reduce, and see its power to transform our array data into virtually any data type we want.</p>
<h3 id="heading-object-oriented-javascript">Object-Oriented JavaScript</h3>
<p>Next we'll get started with object-oriented programming and cover the core idea behind it that makes object oriented programming in JavaScript possible–the constructor function. </p>
<p>Constructor functions make it possible to give our objects shared behavior (functions) through something called the prototype chain. </p>
<p>Through another newer JavaScript feature called classes, we'll cover how we can easily inherit functionality through what's known as prototypical inheritance and extend our classes to share features between them. </p>
<p><a target="_blank" href="https://learn.codeartistry.io/courses/2020-js-bootcamp/lectures/17117787"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LSnOiPfV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-3.cloudinary.com/hl8x9mfjy/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2020-07-13-at-11.27.08-PM.png" alt="Click to access the course" width="600" height="400" loading="lazy"></a>
<em>Click to watch this lecture</em></p>
<h3 id="heading-async-javascript">Async JavaScript</h3>
<p>After that we'll move on to async JavaScript, which is a necessary skill to have and understand if want to create sophisticated JavaScript programs of any kind. </p>
<p>We'll begin with a discussion of what asynchronous code is and how it was handled in the past using callback functions and how this creates problems in our code (such as 'callback hell'). </p>
<p>Fortunately, we'll fix some of the inherent problems with using callbacks through an ES6 feature called a Promise. We'll gain experience using promises in a practical way by getting familiar with the browser's Fetch API, which allows us to make HTTP requests and bring outside data into our apps.</p>
<p>Then, best of all, we'll touch on how to make our promises work and look just like synchronous code so we can easily reason about it with the help of the new async-await syntax for functions. </p>
<p><a target="_blank" href="https://learn.codeartistry.io/courses/2020-js-bootcamp/lectures/17117792"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8X1g6vDX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-4.cloudinary.com/hl8x9mfjy/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2020-07-13-at-11.39.26-PM.png" alt="Click to access the course" width="600" height="400" loading="lazy"></a>
<em>Click to watch this lecture</em></p>
<h3 id="heading-essential-topics">Essential Topics</h3>
<p>We'll wrap up the course with some key skills necessary for starting to build complete JavaScript projects. First of all, we'll do a deep dive into ES Modules, an ES6 feature which allows us to share our JavaScript code across files.</p>
<p>We'll tackle thorny issues such as the <code>this</code> keyword by covering a list of concrete rules to follow in order to figure out it's value in any context, such as in a DOM event handler:</p>
<p><a target="_blank" href="https://learn.codeartistry.io/courses/2020-js-bootcamp/lectures/17117789"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k1WMG7d2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res-4.cloudinary.com/hl8x9mfjy/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2020-07-13-at-11.28.37-PM.png" alt="Click to access the course" width="600" height="400" loading="lazy"></a>
<em>Click to watch this lecture</em></p>
<p>And finally, we'll wrap up the course with a general discussion of imperative versus declarative code, which you should strive for in your coding career, and why. </p>
<h2 id="heading-watch-the-course-now">Watch the course now</h2>
<p>Take this course and, within an afternoon or two, you'll learn concepts that will meaningfully grow your JavaScript skillset and enable you to tackle high-powered front-end libraries like React, Angular, Svelte, Vue, and more with confidence. </p>
<p>Enjoy!</p>
<h2 id="heading-become-a-professional-react-developer">Become a Professional React Developer</h2>
<p>React is hard. You shouldn't have to figure it out yourself.</p>
<p>I've put everything I know about React into a single course, to help you reach your goals in record time:</p>
<p><a target="_blank" href="https://www.thereactbootcamp.com"><strong>Introducing: The React Bootcamp</strong></a></p>
<p><strong>It’s the one course I wish I had when I started learning React.</strong></p>
<p>Click below to try the React Bootcamp for yourself:</p>
<p><a target="_blank" href="https://www.thereactbootcamp.com"><img src="https://reedbarger.nyc3.digitaloceanspaces.com/reactbootcamp/react-bootcamp-cta-alt.png" alt="Click to join the React Bootcamp" width="600" height="400" loading="lazy"></a>
<em>Click to get started</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Full Stack Apps with a Simple Starter Kit Called Reno Expo ]]>
                </title>
                <description>
                    <![CDATA[ By Jackson Bates Building any new project from scratch can be intimidating. There's a lot to decide before you can even start coding to test out your idea. How are you building the front end? Plain CSS, or a framework? Vanilla HTML and JS, or a frame... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/reno-expo-full-stack-starter/</link>
                <guid isPermaLink="false">66d45f42706b9fb1c166b965</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 17 Jun 2020 23:10:42 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9a34740569d1a4ca2431.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jackson Bates</p>
<p>Building any new project from scratch can be intimidating. There's a lot to decide before you can even start coding to test out your idea.</p>
<p>How are you building the front end? Plain CSS, or a framework? Vanilla HTML and JS, or a framework or library such as Vue, React, Angular, or Svelte?</p>
<p>What back end language will you use? JavaScript, Ruby, PHP, Python or something else? Maybe 'serverless'?</p>
<p>What about the database? Relational? MySQL, Postgresql? NoSQL? Mongo? Maybe something 'easy' like Firebase instead?</p>
<p>How will you handle authentication? Maybe a Passport integration that just bundles in a Facebook, Google, Github and LinkedIn login screen?</p>
<p>Whenever I have a cool idea for a little app I want to build myself, I'm always exhausted by the range of options and decisions to be made.</p>
<p>So I took some time to think about my ideal stack, including authentication and deployment considerations, and bundled it all up into one reasonably easy to setup package: Reno Expo.</p>
<h1 id="heading-what-is-reno-expo">What is Reno Expo?</h1>
<p>Reno Expo stands for React, NodeJS, Express, and Postgresql. It also uses Sequelize as the ORM for the database.</p>
<p>At its core it is a very simple Express app that has a Create React App bundled for the front end. It is designed to be deployed to Heroku and has a very simple interface for registering new users and logging in, using JWT for authentication.</p>
<p>Apart from that, it is a completely blank slate. I've intentionally left it pretty empty in terms of CSS styling, so I can plug in any style libraries I want or write my own CSS as required.</p>
<p>Aside from the completely raw version of Reno Expo, I've also made a freeCodeCamp project, the Personal Library, using this stack. It serves as an example of how to integrate a CSS framework, Ant Design in this instance, and also provides some examples of extending the database with Sequelize migrations.</p>
<h2 id="heading-where-can-i-get-it">Where can I get it?</h2>
<p>The code for the two apps can be found here:</p>
<ul>
<li><a target="_blank" href="https://github.com/JacksonBates/reno-expo">Reno Expo Starter Kit</a></li>
<li><a target="_blank" href="https://github.com/JacksonBates/reno-expo-books">Personal Library, built with Reno Expo</a></li>
</ul>
<p>Each has a detailed README.md file, but I'll also explain how to get started with both, and explain how the latter app builds upon the starter kit in this article.</p>
<h2 id="heading-what-do-the-apps-look-like">What do the apps look like?</h2>
<p>Examples for both apps can be found here:</p>
<ul>
<li><a target="_blank" href="http://renoexpo.herokuapp.com/">Reno Expo, example hosted on Heroku</a></li>
<li><a target="_blank" href="https://reno-expo-books.herokuapp.com/">Personal Library, hosted on Heroku</a></li>
</ul>
<p>The starter kit is hideous, frankly. As I stated earlier, it has minimal styling - and I wasn't kidding. The Personal Library shows how one might integrate a CSS framework to get some easy styling wins with minimal effort.</p>
<h2 id="heading-getting-started-with-reno-expo">Getting Started with Reno Expo</h2>
<p>To work with Reno Expo you will need the following installed on your local computer: <a target="_blank" href="https://git-scm.com/">git</a>, <a target="_blank" href="https://nodejs.org/en/download/">Node</a>, npm (bundled with your Node download), and <a target="_blank" href="https://www.postgresql.org/">Postgresql</a>.</p>
<p>Use the latest versions of each if you are starting from scratch, but if you already have other versions of these on you system they may well work just fine. </p>
<p>For the record, I've been developing with these versions: Node 8.16, npm 6.14 and Postgres 10, and my Heroku deployments have been the latest stable versions of all these. </p>
<p>If you run into problems using different versions, either using these versions or try looking for differences in the appropriate change logs to help you get unstuck.</p>
<p>Your Postgres installation will also require a valid user with database creation privileges. Setting this up is outside the scope of this article, but you can find the relevant guides for your environment with an online search for "getting started with postgres windows/mac/ubuntu" etc.</p>
<h3 id="heading-installing-the-starter-kit">Installing the Starter Kit</h3>
<p>To initialise the starter kit, we will use two terminals. Later, I'll share a trick for spinning up your development environment from a single terminal, but for now we'll keep the front end and back end separated.</p>
<p>In terminal one, from the directory in which you wish to create your new app:</p>
<p><code>git clone git@github.com:JacksonBates/reno-expo.git</code></p>
<p>Then navigate to that new folder: <code>cd reno-expo</code></p>
<p>Make a copy of the .env file: <code>cp .env.example .env</code></p>
<p>You will need to adjust the development variables in the new .env file:</p>
<pre><code class="lang-sh">DEVELOPMENT_DATABASE=database_development
DEVELOPMENT_DATABASE_USERNAME=sequelize
DEVELOPMENT_DATABASE_PASSWORD=password
</code></pre>
<p>The development database can be whatever you like, but the username and password will have to match whatever you have configured for your local Postgres installation.</p>
<p>Now install the npm packages for the back end: <code>npm i</code></p>
<p>Next we will create the database using Sequelize. Note, if your Postgres installation isn't set up properly, this is the first bit that will fall over...</p>
<p><code>npx sequelize-cli db:create</code></p>
<p>This will create the database with the name you set in your .env file.</p>
<p>Now we can create the table for our users:</p>
<p><code>npx sequelize-cli db:migrate</code></p>
<p>If this works, you should see some terminal output such as:</p>
<pre><code class="lang-sh">== 20200606113054-create-user: migrating =======
== 20200606113054-create-user: migrated (0.074s)
</code></pre>
<p>If all this has worked, you can now start the back end server with <code>npm start</code>.</p>
<p>Setting up the front end should be more simple. In your second terminal navigate to the client folder: <code>reno-expo/client</code></p>
<p>Install the node modules: <code>npm i</code></p>
<p>Now run the React app with <code>npm start</code>.</p>
<h3 id="heading-single-terminal-launch">Single terminal Launch</h3>
<p>If everything initialises properly, in future you can easily spin up both the React app and Express server with one command from a single terminal:</p>
<p><code>npm run dev</code></p>
<h3 id="heading-check-that-it-works">Check that it works</h3>
<p>In your browser of choice, visit localhost:3000 and you should see a very basic 'Home' page and some links to an Admin and Login page.</p>
<p>Admin should be locked until you log in.</p>
<p>Login will require you to create a user account first. Click 'I don't have an account' and make one via the registration form. You can now log in and test your access to the Admin page.</p>
<p>If all is working, you can begin to develop your app!</p>
<h2 id="heading-building-something-more-substantial-with-reno-expo">Building something more substantial with Reno Expo</h2>
<p>To create the Personal Library there were 3 main things to do: </p>
<ol>
<li>install and implement the Ant Design CSS framework</li>
<li>create the new front end routes / views</li>
<li>extend the api with new database models and controllers</li>
</ol>
<p>After installing Ant Design with <code>npm i antd</code> I added the following line to the existing App.css file in the <code>client/styles</code> folder: <code>@import"~antd/dist/antd.css";</code></p>
<p>This ensures the Ant Design styling will be available throughout the app.</p>
<p>The repo for the Personal Library contains all the amendments, but here are some examples of patterns you could use. Of course, you could roll your own CSS, or use other frameworks such as Material-UI, Bootstrap or others, what follows is just illustrative.</p>
<h3 id="heading-implementing-a-layout">Implementing a layout</h3>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Layout, Menu } <span class="hljs-keyword">from</span> <span class="hljs-string">"antd"</span>;
<span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> { useAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../context/auth"</span>;

<span class="hljs-keyword">const</span> { Content, Sider, Footer } = Layout;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AppLayout</span>(<span class="hljs-params">props</span>) </span>{
  <span class="hljs-keyword">const</span> { setAuthTokens } = useAuth();

  <span class="hljs-keyword">const</span> logout = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();
    setAuthTokens();
    <span class="hljs-built_in">localStorage</span>.removeItem(<span class="hljs-string">"tokens"</span>);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Sider</span> <span class="hljs-attr">breakpoint</span>=<span class="hljs-string">"md"</span> <span class="hljs-attr">collapsedWidth</span>=<span class="hljs-string">"0"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Menu</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">"dark"</span> <span class="hljs-attr">mode</span>=<span class="hljs-string">"inline"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Menu.Item</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"1"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"/"}&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-text"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Menu.Item</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Menu.Item</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"2"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"/<span class="hljs-attr">personal</span>"}&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-text"</span>&gt;</span>Personal Library<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Menu.Item</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Menu.Item</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"3"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"/<span class="hljs-attr">public</span>"}&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-text"</span>&gt;</span>Public Library<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Menu.Item</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Menu.Item</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"4"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"/<span class="hljs-attr">login</span>"} <span class="hljs-attr">onClick</span>=<span class="hljs-string">{logout}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-text"</span>&gt;</span>Log out<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Menu.Item</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Menu</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Sider</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Layout</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">minHeight:</span> "<span class="hljs-attr">100vh</span>" }}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Content</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">margin:</span> "<span class="hljs-attr">24px</span> <span class="hljs-attr">16px</span> <span class="hljs-attr">0</span>" }}&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">padding:</span> <span class="hljs-attr">24</span>, <span class="hljs-attr">background:</span> "#<span class="hljs-attr">fff</span>", <span class="hljs-attr">minHeight:</span> "<span class="hljs-attr">80vh</span>" }}&gt;</span>
            {props.children}
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Content</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Footer</span>&gt;</span>Reno Expo Books<span class="hljs-tag">&lt;/<span class="hljs-name">Footer</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
}
</code></pre>
<p>Apart from a small function handling the auth token, the rest of this uses the components supplied by Ant Design for creating an app with a persistent side bar for navigation, and dynamically rendered content depending on the active component.</p>
<p>Where does the active component get loaded?</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Route } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> { AppLayout } <span class="hljs-keyword">from</span> <span class="hljs-string">"../layouts"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PublicRoute</span>(<span class="hljs-params">{ children, ...rest }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Route</span> {<span class="hljs-attr">...rest</span>}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">AppLayout</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">AppLayout</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Route</span>&gt;</span></span>
  );
}
</code></pre>
<p>Above we have an example of the PublicRoute component. There are some other route components I use, but understanding them should be straightforward enough based on this one.</p>
<p>Our PublicRoute is a React-Router <code>&lt;Route&gt;</code> wrapping the layout from above. </p>
<p>App.js shows examples of these Public Routes being used, for example:</p>
<pre><code class="lang-js">&lt;PublicRoute exact path=<span class="hljs-string">"/"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Home</span> /&gt;</span></span>
&lt;/PublicRoute&gt;
</code></pre>
<p>So in the first two files we can see a reference to <code>children</code>.</p>
<p><code>children</code> is a built in prop in React that references the child components that are nested in parent components.</p>
<p>In the above examples we see the <code>&lt;Home&gt;</code> component as a child of the <code>PublicRoute</code>. In the PublicRoute.js file we see the reference to children, both in the props and being passed directly to the <code>&lt;AppLayout&gt;</code> component. And finally in the AppLayout.js the <code>&lt;Content&gt;</code> component also contains the children. In all these cases, children refers to that <code>&lt;Home&gt;</code> component passed from App.js.</p>
<p>In practice, this means any of the components passed from App.js on public or private routes will be rendered into the content area on our Layout, leaving the navigation sidebar untouched.</p>
<p>Other files in the client folder should give ample examples of how things like the Login form can be replaced with the Ant Design framework after some small modifications.</p>
<h3 id="heading-making-changes-to-the-back-end">Making changes to the back end</h3>
<p>The other main thing to develop when working with Reno Expo is the api itself - after all, it's useful being able to register a user and have them log in, but most apps require more than that to be really useful.</p>
<p>For the purposes of my version of the Personal Library we needed to implement a number of new api endpoints, and create some new database tables to store book and comment data.</p>
<p>It's worth highlighting here that in these examples I'm working backwards. Normally I'd create the database migrations and models first, then build the controller methods and api routes afterwards. I present them 'backwards' here so we can follow the logic from our goal back through how it was implemented piece by piece.</p>
<p>The file <code>reno-expo-books/app/router/router.js</code> contains all the routes for the project, but I'll share two examples here for illustration.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Public route</span>
app.get(<span class="hljs-string">"/api/books"</span>, booksController.getBooks);


<span class="hljs-comment">// Private route</span>
app.get(
    <span class="hljs-string">"/api/user/books"</span>,
    [authJwt.verifyToken],
    booksController.getUserBooks
  );
</code></pre>
<p>Adding public routes is simple enough, we just need to define the http method, the api endpoint and the controller method that will handle the request, e.g. a GET request, to <code>api/books</code> handled by the booksController <code>getBooks</code> method.</p>
<p>The JWT auth that we already have available from the Reno Expo starter makes the private routes pretty simple too. All we need to do is include the middleware for verifying the token, <code>[authJwt.verifyToken]</code> in the example above.</p>
<p>The controllers for these endpoints, i.e. the code that processes the requests, are also reasonably straightforward, although using Sequelize for the first time can have a bit of a learning curve.</p>
<p>Here's an example of the public 'getBooks' method referenced above:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> db = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../../models/index"</span>);
<span class="hljs-keyword">const</span> Sequelize = <span class="hljs-built_in">require</span>(<span class="hljs-string">"sequelize"</span>);
<span class="hljs-keyword">const</span> Book = db.Book;
<span class="hljs-keyword">const</span> BookComment = db.BookComment;

<span class="hljs-comment">// Public routes</span>

<span class="hljs-built_in">exports</span>.getBooks = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  Book.findAll({
    <span class="hljs-attr">where</span>: { <span class="hljs-attr">userId</span>: <span class="hljs-literal">null</span> },
    <span class="hljs-attr">attributes</span>: {
      <span class="hljs-attr">include</span>: [
        [
          Sequelize.fn(<span class="hljs-string">"COUNT"</span>, Sequelize.col(<span class="hljs-string">"BookComments.id"</span>)),
          <span class="hljs-string">"commentcount"</span>,
        ],
      ],
      <span class="hljs-attr">exclude</span>: [<span class="hljs-string">"createdAt"</span>, <span class="hljs-string">"updatedAt"</span>],
    },
    <span class="hljs-attr">include</span>: {
      <span class="hljs-attr">model</span>: BookComment,
      <span class="hljs-attr">attributes</span>: [],
    },
    <span class="hljs-attr">group</span>: [<span class="hljs-string">"Book.id"</span>],
  })
    .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> res.status(<span class="hljs-number">200</span>).json(data))
    .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> res.send(error));
};
</code></pre>
<p>The imports at the top of the file provide the database models and the Sequelize library.</p>
<p>The <code>getBooks</code> method looks complicated, but it is made up of a few relatively simple parts.</p>
<p>Firstly we call the <code>Book</code> model. The model is an ORM representation of the books table - we'll look at how we create that table soon.</p>
<p>Sequelize, like most ORMs, provides not only a schema or description of the table, but also methods that can be called upon the model. In this case we call <code>Book.findAll({...})</code>, which will return all the books it can find that match particular parameters we pass to it.</p>
<p>In this particular instance I wanted to receive something like this:</p>
<pre><code class="lang-json">[
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"The Hobbit"</span>,
    <span class="hljs-attr">"commentcount"</span>: <span class="hljs-number">3</span>
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">2</span>,
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"The Lord of the Rings"</span>,
    <span class="hljs-attr">"commentcount"</span>: <span class="hljs-number">2</span>
  }
]
</code></pre>
<p>In the findAll method, first we pass the <code>where</code> parameters. If you are familiar with SQL, it should be pretty clear what this does. In the example above we want all books where the userId is null. This is because we only want to return the public books from this controller, so only those with no user attached to them.</p>
<p>Next, the <code>attributes</code> describes the shape of the response, or the data we expect back. The exclude section is easier to understand, so I'll explain it first. The books table has columns for the created_at and updated_at timestamps for each record. Since we don't want these in our json response, we can omit them explicitly in the exclude section.</p>
<p>Our include portion of the attributes is more complicated. In raw SQL we would count the number of associated comments like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> <span class="hljs-string">"Books"</span>.<span class="hljs-string">"id"</span>, <span class="hljs-string">"Books"</span>.<span class="hljs-string">"title"</span>, <span class="hljs-keyword">COUNT</span>(<span class="hljs-string">"BookComments"</span>.<span class="hljs-string">"id"</span>) <span class="hljs-keyword">AS</span> <span class="hljs-string">"commentcount"</span>
<span class="hljs-keyword">FROM</span> <span class="hljs-string">"Books"</span>
<span class="hljs-keyword">JOIN</span> <span class="hljs-string">"BookComments"</span> <span class="hljs-keyword">ON</span> <span class="hljs-string">"BookComments"</span>.<span class="hljs-string">"bookId"</span> = <span class="hljs-string">"Books"</span>.<span class="hljs-string">"id"</span>
<span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span> <span class="hljs-string">"Books"</span>.<span class="hljs-string">"id"</span>;
</code></pre>
<p>The SQL COUNT function counts all the records in the BookComments.id column, and the GROUP BY function limits the counted comments to each book, by ID.</p>
<p>It's worth pointing out that commentcount is not a column on the books table, rather it is a calculated column derived from the thing we ask the database to count for us.</p>
<p>Sequelize gives us access to the count function via its library.</p>
<p>The relevant function is included in the attributes above like this:</p>
<pre><code class="lang-js">[Sequelize.fn(<span class="hljs-string">"COUNT"</span>, Sequelize.col(<span class="hljs-string">"BookComments.id"</span>)),<span class="hljs-string">"commentcount"</span>]
</code></pre>
<p>I.e. "Call the Sequelize function 'COUNT', count the columns for BookComments.id, and name the generated column 'commentcount'</p>
<p>This provides our count function just like in the SQL version. All that's left is to include the <code>group: ['Book.id']</code> as an extra parameter of the findAll method on the Book model.</p>
<p>The other part you may have noticed in the findAll method parameters is this:</p>
<pre><code class="lang-js">include: {
  <span class="hljs-attr">model</span>: BookComment,
  <span class="hljs-attr">attributes</span>: [],
},
</code></pre>
<p>That's right, <em>another</em> include. Notice that this one is not nested in the attributes, but is its peer. This include acts much the same way as the JOIN statement in the SQL above. It means we want to include the BookComment model, but we don't need to add any attributes since we don't want to reference any of the columns it has directly - we just use it in the count function.</p>
<h3 id="heading-making-changes-to-the-database">Making changes to the database</h3>
<p>The final thing we need to understand to be productive with Sequelize is the migrations for making changes to the database.</p>
<p>Migrations can be thought of as source control for your database.</p>
<p>While you can amend a database directly by creating new tables, adding columns, introducing constraints, changing data types or whatever else, using migrations allows you to make experimental changes with the ability to roll them back easily, and be able to share your development on a database with other people that do not have to struggle with keeping their local databases, and prod, in sync.</p>
<p>Migrations are essentially code that tell your database how to change, and how to undo the change that was introduced, should that be necessary.</p>
<p>Here is the migration for creating the books table:</p>
<pre><code class="lang-js"><span class="hljs-meta">'use strict'</span>;
<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">up</span>: <span class="hljs-function">(<span class="hljs-params">queryInterface, Sequelize</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> queryInterface.createTable(<span class="hljs-string">'Books'</span>, {
      <span class="hljs-attr">id</span>: {
        <span class="hljs-attr">allowNull</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">autoIncrement</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">primaryKey</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">type</span>: Sequelize.INTEGER
      },
      <span class="hljs-attr">title</span>: {
        <span class="hljs-attr">type</span>: Sequelize.STRING
      },
      <span class="hljs-attr">createdAt</span>: {
        <span class="hljs-attr">allowNull</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">type</span>: Sequelize.DATE
      },
      <span class="hljs-attr">updatedAt</span>: {
        <span class="hljs-attr">allowNull</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">type</span>: Sequelize.DATE
      }
    });
  },
  <span class="hljs-attr">down</span>: <span class="hljs-function">(<span class="hljs-params">queryInterface, Sequelize</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> queryInterface.dropTable(<span class="hljs-string">'Books'</span>);
  }
};
</code></pre>
<p>This migration is a module that exports two functions: <code>up</code> and <code>down</code></p>
<p>The <code>up</code> function makes the changes, while the <code>down</code> function undoes any of the changes that were introduced.</p>
<p>So here we see that up creates a table called 'Books' with the columns id, title, created_at and updated_at. Each column has some associated qualities as well, such as data type, and whether it can contain a null value, for example.</p>
<p>The down function simply drops the table.</p>
<p>I won't share all of the next migration, i.e. the one for creating the Book Comment table, but I will show a snippet from it's up function that defines the bookId column:</p>
<pre><code class="lang-js">bookId: {
  <span class="hljs-attr">type</span>: Sequelize.INTEGER,
  <span class="hljs-attr">onDelete</span>: <span class="hljs-string">"CASCADE"</span>,
  <span class="hljs-attr">references</span>: {
    <span class="hljs-attr">model</span>: { <span class="hljs-attr">tableName</span>: <span class="hljs-string">"Books"</span> },
    <span class="hljs-attr">key</span>: <span class="hljs-string">"id"</span>,
  },
  <span class="hljs-attr">allowNull</span>: <span class="hljs-literal">false</span>,
},
</code></pre>
<p>The interesting things to note here are the <code>onDelete</code> property, which is set to "CASCADE" and the <code>references</code> property which links the books table via the id column. This sets up the relationship between a book and its comments. The onDelete property tells the database what to do if a book is deleted: that deletion action should cascade to all associated comments. That is, if I delete 'The Hobbit' all the comments relating to 'The Hobbit' get deleted too.</p>
<p>The last thing to be aware of is that these migrations are also supported by models. The BookComment model looks like this:</p>
<pre><code class="lang-js"><span class="hljs-meta">"use strict"</span>;
<span class="hljs-built_in">module</span>.exports = <span class="hljs-function">(<span class="hljs-params">sequelize, DataTypes</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> BookComment = sequelize.define(
    <span class="hljs-string">"BookComment"</span>,
    {
      <span class="hljs-attr">comment</span>: DataTypes.TEXT,
      <span class="hljs-attr">bookId</span>: {
        <span class="hljs-attr">type</span>: DataTypes.INTEGER,
        <span class="hljs-attr">references</span>: {
          <span class="hljs-attr">model</span>: <span class="hljs-string">"Books"</span>,
          <span class="hljs-attr">key</span>: <span class="hljs-string">"id"</span>,
        },
      },
    },
    {}
  );
  BookComment.associate = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">models</span>) </span>{
    <span class="hljs-comment">// associations can be defined here</span>
    BookComment.belongsTo(models.Book, {
      <span class="hljs-attr">foreignKey</span>: <span class="hljs-string">"bookId"</span>,
    });
  };
  <span class="hljs-keyword">return</span> BookComment;
};
</code></pre>
<p>You will notice some similarities between this and the migration. It has two parts, the Model definition and the model associations. These help reinforce the relationship between the various tables as necessary.</p>
<p>To create tables from scratch, you can use a command like this:</p>
<p><code>npx sequelize-cli model:generate --name Post --attributes post:text</code></p>
<p>This will automatically generate a model skeleton and a migration skeleton for a <code>posts</code> table with the column 'post'. You can then fill in the migration and model with whatever other column details or associations are relevant.</p>
<p>If you just want to amend an existing table, for example, to change a data type, or add a column, you can use a command to only generate a migration:</p>
<p><code>npx sequelize-cli migration:generate --name add-userId-to-posts</code></p>
<p>You can then make the changes to the existing model and new migration file as necessary.</p>
<h3 id="heading-applying-database-changes">Applying database changes</h3>
<p>Simply writing the code to update the database is not enough, you also need to run the migrations for each database your code works on - i.e. your local dev machine, maybe your staging server if you have one, and also your production server.</p>
<p>The command for running these is:</p>
<p><code>npx sequelize-cli db:migrate</code></p>
<p>You can roll back migrations as well: </p>
<p><code>npx sequelize-cli db:migrate:undo</code></p>
<h2 id="heading-happy-coding">Happy coding!</h2>
<p>That's it! As I mentioned above, I personally deploy everything I make with these to Heroku, and there are detailed instructions for the particulars of deploying them to Heroku in the README.md of Reno Expo. This also includes the commands for running migrations on Heroku's server.</p>
<p>There is a lot to take in here. But if you fundamentally understand Express and React, and are willing to dig in to the Sequelize docs when needed, you can build pretty much anything you can imagine that benefits from a relational database using this starter kit.</p>
<p>It's not quite as fully featured as a proper MVC framework like Rails, Laravel, Sails, or Nest, but I happen to like that there is less cruft and less <code>magic</code> hidden in the internals of this. It is, after all, just a Create React App bundled with a light server and an ORM package. The rest is up to you.</p>
<hr>
<p>If you made it to the end of this article, and especially if you build anything with Reno Expo, I would love to hear from you. You can contact me on Twitter: <a target="_blank" href="https://twitter.com/JacksonBates">@JacksonBates</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Full-Stack Yelp Clone with React & GraphQL (Dune World Edition) ]]>
                </title>
                <description>
                    <![CDATA[ By Sezgi Ulucam I must not fear. Fear is the mind-killer. Fear is the little-death that brings total obliteration. I will face my fear. I will permit it to pass over me and through me. And when it has gone past I will turn the inner eye to see its ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-a-full-stack-yelp-clone-with-react-graphql/</link>
                <guid isPermaLink="false">66d460ee733861e3a22a735d</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GraphQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 05 May 2020 19:05:25 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/05/article-cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Sezgi Ulucam</p>
<blockquote>
<p>I must not fear. Fear is the mind-killer. Fear is the little-death that brings total obliteration. I will face my fear. I will permit it to pass over me and through me. And when it has gone past I will turn the inner eye to see its path. Where the fear has gone there will be nothing. Only I will remain.
- "Litany Against Fear," Frank Herbert, Dune</p>
</blockquote>
<p>You may be wondering, "What does fear have to do with a React app?" First of all, there's nothing to fear in a React app. In fact, in this particular app, we banned fear. Isn't that nice?</p>
<p>Now that you're ready to be fearless, let's discuss our app. It's a mini Yelp clone where instead of reviewing restaurants, users review planets from the classic sci-fi series, <a target="_blank" href="https://en.wikipedia.org/wiki/Dune_(franchise)">Dune</a>. (Why? Because there's a new Dune movie coming out... but back to the main point.)</p>
<p>To build our full-stack app, we'll use technologies that make our lives easy.</p>
<ol>
<li><a target="_blank" href="https://reactjs.org/">React</a>: Intuitive, compositional front-end framework, because our brains like to compose things.</li>
<li><a target="_blank" href="https://graphql.org/">GraphQL</a>: You may have heard many reasons why GraphQL is awesome. By far, the most important one is <strong>developer productivity and happiness</strong>.</li>
<li><a target="_blank" href="http://hasura.io/">Hasura</a>: Set up an auto-generated GraphQL API on top of a Postgres database in under 30 seconds.</li>
<li><a target="_blank" href="https://heroku.com/">Heroku</a>: To host our database.</li>
</ol>
<h2 id="heading-and-graphql-gives-me-happiness-how">And GraphQL gives me happiness how?</h2>
<p>I see you're a skeptical one. But you'll most likely come around as soon as you spend some time with GraphiQL (the GraphQL playground). </p>
<p>Using GraphQL is a breeze for the front-end developer, compared to the old ways of clunky REST endpoints. GraphQL gives you a single endpoint that listens to all your troubles... I mean queries. It's such a great listener that you can tell it exactly what you want, and it will give it to you, nothing less and nothing more.</p>
<p>Feeling psyched about this therapeutic experience? Let's dive into the tutorial so you can try it ASAP!</p>
<p>?? <a target="_blank" href="https://github.com/hasura/yelp-clone-react"><strong>Here's the repo</strong></a> if you'd like to code along.</p>
<h1 id="heading-part-1-search"><strong>P</strong>art <strong>1: S</strong>earch</h1>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/lrYo_n-9LM8" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-step-1-deploy-to-heroku"><strong>S</strong>tep <strong>1: D</strong>eploy to Heroku</h2>
<p>The first step of every good journey is sitting down with some hot tea and sipping it calmly. Once we've done that, we can deploy to Heroku from the <a target="_blank" href="http://hasura.io/">Hasura website</a>. This will set us up with everything we need: a Postgres database, our Hasura GraphQL engine, and some snacks for the journey.</p>
<p><img src="https://draftin.com/images/73048?token=L5lFsg6SzmNzsdweEfn9uOLF6qJwkU1loz9LvhE-2PP7sFmiI9nZZ6z87S0pZZZ1xikaO2Z_6GyGPxOzyt170p8" alt="black-books.png" width="600" height="400" loading="lazy">
<em>Not at all a Dune reference</em></p>
<h2 id="heading-step-2-create-planets-table">Step 2: Create planets table</h2>
<p>Our users want to review planets. So we create a Postgres table via the Hasura console to store our planet data. Of note is the evil planet, Giedi Prime, which has been drawing attention with its unconventional cuisine.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p1-s2-1.png" alt="Planets table" width="600" height="400" loading="lazy"></p>
<p>Meanwhile in the GraphiQL tab: Hasura has auto-generated our GraphQL schema! Play around with the Explorer here ??</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p1-s2-schema-1.png" alt="GraphiQL Explorer" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-3-create-react-app"><strong>S</strong>tep <strong>3: C</strong>reate React app</h2>
<p>We'll need a UI for our app, so we create a React app and install some libraries for GraphQL requests, routing, and styles. (Make sure you have <a target="_blank" href="https://nodejs.org/">Node</a> installed first.)</p>
<pre><code class="lang-bash">&gt; npx create-react-app melange
&gt; <span class="hljs-built_in">cd</span> melange
&gt; npm install graphql @apollo/client react-router-dom @emotion/styled @emotion/core
&gt; npm start
</code></pre>
<h2 id="heading-step-4-set-up-apollo-client"><strong>S</strong>tep <strong>4: S</strong>et up Apollo Client</h2>
<p><a target="_blank" href="https://www.apollographql.com/docs/react/v3.0-beta">Apollo Client</a> will help us with our GraphQL network requests and caching, so we can avoid all that grunt work. We also make our first query and list our planets! Our app is starting to shape up.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { render } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom"</span>;
<span class="hljs-keyword">import</span> { ApolloProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;
<span class="hljs-keyword">import</span> { ApolloClient, HttpLink, InMemoryCache } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;
<span class="hljs-keyword">import</span> Planets <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Planets"</span>;

<span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> ApolloClient({
  <span class="hljs-attr">cache</span>: <span class="hljs-keyword">new</span> InMemoryCache(),
  <span class="hljs-attr">link</span>: <span class="hljs-keyword">new</span> HttpLink({
    <span class="hljs-attr">uri</span>: <span class="hljs-string">"[YOUR HASURA GRAPHQL ENDPOINT]"</span>,
  }),
});

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ApolloProvider</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{client}</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Planets</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ApolloProvider</span>&gt;</span></span>
);

render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>, <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
</code></pre>
<p>We test our GraphQL query in the Hasura console before copy-pasting it into our code.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p1-s4-test-query-2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useQuery, gql } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;

<span class="hljs-keyword">const</span> PLANETS = gql<span class="hljs-string">`
  {
    planets {
      id
      name
      cuisine
    }
  }
`</span>;

<span class="hljs-keyword">const</span> Planets = <span class="hljs-function">(<span class="hljs-params">{ newPlanets }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { loading, error, data } = useQuery(PLANETS);

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading ...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error :(<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-keyword">return</span> data.planets.map(<span class="hljs-function">(<span class="hljs-params">{id, name, cuisine}</span>) =&gt;</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{id}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
          {name} | {cuisine}
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  ));
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Planets;
</code></pre>
<h2 id="heading-step-5-style-list"><strong>S</strong>tep <strong>5: S</strong>tyle list</h2>
<p>Our planet list is nice and all, but it needs a little makeover with <a target="_blank" href="https://emotion.sh/">Emotion</a> (see <a target="_blank" href="https://github.com/hasura/yelp-clone-react">repo</a> for full styles).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p1-s5-style-1.png" alt="Styled list of planets" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-6-search-form-amp-state"><strong>S</strong>tep <strong>6: S</strong>earch form &amp; state</h2>
<p>Our users want to search for planets and order them by name. So we add a search form that queries our endpoint with a search string, and pass in the results to <code>Planets</code> to update our planet list. We also use <a target="_blank" href="https://reactjs.org/docs/hooks-reference.html">React Hooks</a> to manage our app state.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useLazyQuery, gql } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;
<span class="hljs-keyword">import</span> Search <span class="hljs-keyword">from</span> <span class="hljs-string">"./Search"</span>;
<span class="hljs-keyword">import</span> Planets <span class="hljs-keyword">from</span> <span class="hljs-string">"./Planets"</span>;

<span class="hljs-keyword">const</span> SEARCH = gql<span class="hljs-string">`
  query Search($match: String) {
    planets(order_by: { name: asc }, where: { name: { _ilike: $match } }) {
      name
      cuisine
      id
    }
  }
`</span>;

<span class="hljs-keyword">const</span> PlanetSearch = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [inputVal, setInputVal] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [search, { loading, error, data }] = useLazyQuery(SEARCH);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Search</span>
        <span class="hljs-attr">inputVal</span>=<span class="hljs-string">{inputVal}</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setInputVal(e.target.value)}
        onSearch={() =&gt; search({ variables: { match: `%${inputVal}%` } })}
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Planets</span> <span class="hljs-attr">newPlanets</span>=<span class="hljs-string">{data</span> ? <span class="hljs-attr">data.planets</span> <span class="hljs-attr">:</span> <span class="hljs-attr">null</span>} /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> PlanetSearch;
</code></pre>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useQuery, gql } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;
<span class="hljs-keyword">import</span> { List, ListItem } <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/List"</span>;
<span class="hljs-keyword">import</span> { Badge } <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/Badge"</span>;

<span class="hljs-keyword">const</span> PLANETS = gql<span class="hljs-string">`
  {
    planets {
      id
      name
      cuisine
    }
  }
`</span>;

<span class="hljs-keyword">const</span> Planets = <span class="hljs-function">(<span class="hljs-params">{ newPlanets }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { loading, error, data } = useQuery(PLANETS);

  <span class="hljs-keyword">const</span> renderPlanets = <span class="hljs-function">(<span class="hljs-params">planets</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> planets.map(<span class="hljs-function">(<span class="hljs-params">{ id, name, cuisine }</span>) =&gt;</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ListItem</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{id}</span>&gt;</span>
        {name} <span class="hljs-tag">&lt;<span class="hljs-name">Badge</span>&gt;</span>{cuisine}<span class="hljs-tag">&lt;/<span class="hljs-name">Badge</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">ListItem</span>&gt;</span></span>
    ));
  };

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading ...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error :(<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">List</span>&gt;</span>{renderPlanets(newPlanets || data.planets)}<span class="hljs-tag">&lt;/<span class="hljs-name">List</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Planets;
</code></pre>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> styled <span class="hljs-keyword">from</span> <span class="hljs-string">"@emotion/styled"</span>;
<span class="hljs-keyword">import</span> { Input, Button } <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/Form"</span>;

<span class="hljs-keyword">const</span> SearchForm = styled.div<span class="hljs-string">`
  display: flex;
  align-items: center;
  &gt; button {
    margin-left: 1rem;
  }
`</span>;

<span class="hljs-keyword">const</span> Search = <span class="hljs-function">(<span class="hljs-params">{ inputVal, onChange, onSearch }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">SearchForm</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Input</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{inputVal}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{onChange}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onSearch}</span>&gt;</span>Search<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">SearchForm</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Search;
</code></pre>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { render } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom"</span>;
<span class="hljs-keyword">import</span> { ApolloProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;
<span class="hljs-keyword">import</span> { ApolloClient, HttpLink, InMemoryCache } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;
<span class="hljs-keyword">import</span> PlanetSearch <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/PlanetSearch"</span>;
<span class="hljs-keyword">import</span> Logo <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/shared/Logo"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>;

<span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> ApolloClient({
  <span class="hljs-attr">cache</span>: <span class="hljs-keyword">new</span> InMemoryCache(),
  <span class="hljs-attr">link</span>: <span class="hljs-keyword">new</span> HttpLink({
    <span class="hljs-attr">uri</span>: <span class="hljs-string">"[YOUR HASURA GRAPHQL ENDPOINT]"</span>,
  }),
});

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ApolloProvider</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{client}</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Logo</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PlanetSearch</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ApolloProvider</span>&gt;</span></span>
);

render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>, <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
</code></pre>
<h2 id="heading-step-7-be-proud"><strong>S</strong>tep <strong>7: B</strong>e proud</h2>
<p>We've already implemented our planet list and search features! We lovingly gaze upon our handiwork, take a few selfies together, and move on to reviews.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/pt1-s7-finito.png" alt="Planet list with search" width="600" height="400" loading="lazy"></p>
<h1 id="heading-part-2-live-reviews"><strong>P</strong>art <strong>2: L</strong>ive reviews</h1>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/3kzXxc1XvRw" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-step-1-create-reviews-table"><strong>S</strong>tep <strong>1: C</strong>reate reviews table</h2>
<p>Our users will be visiting these planets, and writing reviews about their experience. We create a table via the Hasura console for our review data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p2-s1-reviews-table-2.png" alt="Reviews table" width="600" height="400" loading="lazy"></p>
<p>We add a foreign key from the <code>planet_id</code> column to the <code>id</code> column in the <code>planets</code> table, to indicate that <code>planet_id</code>s of <code>reviews</code> have to match <code>id</code>'s of <code>planets</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p2-s1-foreign-key-2.png" alt="Foreign keys" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-2-track-relationships"><strong>S</strong>tep <strong>2: T</strong>rack relationships</h2>
<p>Each planet has multiple reviews, while each review has one planet: a one-to-many relationship. We create and track this relationship via the Hasura console, so it can be exposed in our GraphQL schema.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p2-s2-track-2.png" alt="Tracking relationships" width="600" height="400" loading="lazy"></p>
<p>Now we can query reviews for each planet in the Explorer!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p2-s3-explorer-3.png" alt="Querying planet reviews" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-3-set-up-routing"><strong>S</strong>tep <strong>3: S</strong>et up routing</h2>
<p>We want to be able to click on a planet and view its reviews on a separate page. We set up routing with React Router, and list reviews on the planet page.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { render } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom"</span>;
<span class="hljs-keyword">import</span> { ApolloProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;
<span class="hljs-keyword">import</span> { ApolloClient, HttpLink, InMemoryCache } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;
<span class="hljs-keyword">import</span> { BrowserRouter, Switch, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> PlanetSearch <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/PlanetSearch"</span>;
<span class="hljs-keyword">import</span> Planet <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Planet"</span>;
<span class="hljs-keyword">import</span> Logo <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/shared/Logo"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>;

<span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> ApolloClient({
  <span class="hljs-attr">cache</span>: <span class="hljs-keyword">new</span> InMemoryCache(),
  <span class="hljs-attr">link</span>: <span class="hljs-keyword">new</span> HttpLink({
    <span class="hljs-attr">uri</span>: <span class="hljs-string">"[YOUR HASURA GRAPHQL ENDPOINT]"</span>,
  }),
});

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BrowserRouter</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ApolloProvider</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{client}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Logo</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Switch</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/planet/:id"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Planet}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{PlanetSearch}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Switch</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ApolloProvider</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">BrowserRouter</span>&gt;</span></span>
);

render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>, <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
</code></pre>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useQuery, gql } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;
<span class="hljs-keyword">import</span> { List, ListItem } <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/List"</span>;
<span class="hljs-keyword">import</span> { Badge } <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/Badge"</span>;

<span class="hljs-keyword">const</span> PLANET = gql<span class="hljs-string">`
  query Planet($id: uuid!) {
    planets_by_pk(id: $id) {
      id
      name
      cuisine
      reviews {
        id
        body
      }
    }
  }
`</span>;

<span class="hljs-keyword">const</span> Planet = <span class="hljs-function">(<span class="hljs-params">{
  match: {
    params: { id },
  },
}</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { loading, error, data } = useQuery(PLANET, {
    <span class="hljs-attr">variables</span>: { id },
  });

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading ...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error :(<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-keyword">const</span> { name, cuisine, reviews } = data.planets_by_pk;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
        {name} <span class="hljs-tag">&lt;<span class="hljs-name">Badge</span>&gt;</span>{cuisine}<span class="hljs-tag">&lt;/<span class="hljs-name">Badge</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">List</span>&gt;</span>
        {reviews.map((review) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">ListItem</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{review.id}</span>&gt;</span>{review.body}<span class="hljs-tag">&lt;/<span class="hljs-name">ListItem</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">List</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Planet;
</code></pre>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useQuery, gql } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;
<span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> { List, ListItemWithLink } <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/List"</span>;
<span class="hljs-keyword">import</span> { Badge } <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/Badge"</span>;

<span class="hljs-keyword">const</span> PLANETS = gql<span class="hljs-string">`
  {
    planets {
      id
      name
      cuisine
    }
  }
`</span>;

<span class="hljs-keyword">const</span> Planets = <span class="hljs-function">(<span class="hljs-params">{ newPlanets }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { loading, error, data } = useQuery(PLANETS);

  <span class="hljs-keyword">const</span> renderPlanets = <span class="hljs-function">(<span class="hljs-params">planets</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> planets.map(<span class="hljs-function">(<span class="hljs-params">{ id, name, cuisine }</span>) =&gt;</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ListItemWithLink</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{id}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>`/<span class="hljs-attr">planet</span>/${<span class="hljs-attr">id</span>}`}&gt;</span>
          {name} <span class="hljs-tag">&lt;<span class="hljs-name">Badge</span>&gt;</span>{cuisine}<span class="hljs-tag">&lt;/<span class="hljs-name">Badge</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">ListItemWithLink</span>&gt;</span></span>
    ));
  };

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading ...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error :(<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">List</span>&gt;</span>{renderPlanets(newPlanets || data.planets)}<span class="hljs-tag">&lt;/<span class="hljs-name">List</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Planets;
</code></pre>
<h2 id="heading-step-4-set-up-subscriptions"><strong>S</strong>tep <strong>4: S</strong>et up subscriptions</h2>
<p>We install new libraries and set up Apollo Client to support subscriptions. Then, we change our reviews query to a subscription so it can show live updates.</p>
<pre><code class="lang-bash">&gt; npm install @apollo/link-ws subscriptions-transport-ws
</code></pre>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { render } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom"</span>;
<span class="hljs-keyword">import</span> {
  ApolloProvider,
  ApolloClient,
  HttpLink,
  InMemoryCache,
  split,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;
<span class="hljs-keyword">import</span> { getMainDefinition } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client/utilities"</span>;
<span class="hljs-keyword">import</span> { WebSocketLink } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/link-ws"</span>;
<span class="hljs-keyword">import</span> { BrowserRouter, Switch, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> PlanetSearch <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/PlanetSearch"</span>;
<span class="hljs-keyword">import</span> Planet <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Planet"</span>;
<span class="hljs-keyword">import</span> Logo <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/shared/Logo"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>;

<span class="hljs-keyword">const</span> GRAPHQL_ENDPOINT = <span class="hljs-string">"[YOUR HASURA GRAPHQL ENDPOINT]"</span>;

<span class="hljs-keyword">const</span> httpLink = <span class="hljs-keyword">new</span> HttpLink({
  <span class="hljs-attr">uri</span>: <span class="hljs-string">`https://<span class="hljs-subst">${GRAPHQL_ENDPOINT}</span>`</span>,
});

<span class="hljs-keyword">const</span> wsLink = <span class="hljs-keyword">new</span> WebSocketLink({
  <span class="hljs-attr">uri</span>: <span class="hljs-string">`ws://<span class="hljs-subst">${GRAPHQL_ENDPOINT}</span>`</span>,
  <span class="hljs-attr">options</span>: {
    <span class="hljs-attr">reconnect</span>: <span class="hljs-literal">true</span>,
  },
});

<span class="hljs-keyword">const</span> splitLink = split(
  <span class="hljs-function">(<span class="hljs-params">{ query }</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> definition = getMainDefinition(query);
    <span class="hljs-keyword">return</span> (
      definition.kind === <span class="hljs-string">"OperationDefinition"</span> &amp;&amp;
      definition.operation === <span class="hljs-string">"subscription"</span>
    );
  },
  wsLink,
  httpLink
);

<span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> ApolloClient({
  <span class="hljs-attr">cache</span>: <span class="hljs-keyword">new</span> InMemoryCache(),
  <span class="hljs-attr">link</span>: splitLink,
});

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BrowserRouter</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ApolloProvider</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{client}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Logo</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Switch</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/planet/:id"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Planet}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{PlanetSearch}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Switch</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ApolloProvider</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">BrowserRouter</span>&gt;</span></span>
);

render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>, <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
</code></pre>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useSubscription, gql } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;
<span class="hljs-keyword">import</span> { List, ListItem } <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/List"</span>;
<span class="hljs-keyword">import</span> { Badge } <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/Badge"</span>;

<span class="hljs-keyword">const</span> PLANET = gql<span class="hljs-string">`
  subscription Planet($id: uuid!) {
    planets_by_pk(id: $id) {
      id
      name
      cuisine
      reviews {
        id
        body
      }
    }
  }
`</span>;

<span class="hljs-keyword">const</span> Planet = <span class="hljs-function">(<span class="hljs-params">{
  match: {
    params: { id },
  },
}</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { loading, error, data } = useSubscription(PLANET, {
    <span class="hljs-attr">variables</span>: { id },
  });

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading ...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error :(<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-keyword">const</span> { name, cuisine, reviews } = data.planets_by_pk;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
        {name} <span class="hljs-tag">&lt;<span class="hljs-name">Badge</span>&gt;</span>{cuisine}<span class="hljs-tag">&lt;/<span class="hljs-name">Badge</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">List</span>&gt;</span>
        {reviews.map((review) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">ListItem</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{review.id}</span>&gt;</span>{review.body}<span class="hljs-tag">&lt;/<span class="hljs-name">ListItem</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">List</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Planet;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p2-s5-finale-2.png" alt="Planet page with live reviews" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-5-do-a-sandworm-dance"><strong>S</strong>tep <strong>5: D</strong>o a sandworm dance</h2>
<p>We've implemented planets with live reviews! Do a little dance to celebrate before getting down to serious business.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/worm-dance.gif" alt="Worm dance" width="600" height="400" loading="lazy"></p>
<h1 id="heading-part-3-business-logic"><strong>P</strong>art <strong>3: B</strong>usiness logic</h1>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/picA-ORNNH8" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-step-1-add-input-form"><strong>S</strong>tep <strong>1: A</strong>dd input form</h2>
<p>We want a way to submit reviews through our UI. We rename our search form to be a generic <code>InputForm</code> and add it above the review list.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useSubscription, gql } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;
<span class="hljs-keyword">import</span> { List, ListItem } <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/List"</span>;
<span class="hljs-keyword">import</span> { Badge } <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/Badge"</span>;
<span class="hljs-keyword">import</span> InputForm <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/InputForm"</span>;

<span class="hljs-keyword">const</span> PLANET = gql<span class="hljs-string">`
  subscription Planet($id: uuid!) {
    planets_by_pk(id: $id) {
      id
      name
      cuisine
      reviews(order_by: { created_at: desc }) {
        id
        body
        created_at
      }
    }
  }
`</span>;

<span class="hljs-keyword">const</span> Planet = <span class="hljs-function">(<span class="hljs-params">{
  match: {
    params: { id },
  },
}</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [inputVal, setInputVal] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> { loading, error, data } = useSubscription(PLANET, {
    <span class="hljs-attr">variables</span>: { id },
  });

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading ...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error :(<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-keyword">const</span> { name, cuisine, reviews } = data.planets_by_pk;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
        {name} <span class="hljs-tag">&lt;<span class="hljs-name">Badge</span>&gt;</span>{cuisine}<span class="hljs-tag">&lt;/<span class="hljs-name">Badge</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">InputForm</span>
        <span class="hljs-attr">inputVal</span>=<span class="hljs-string">{inputVal}</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setInputVal(e.target.value)}
        onSubmit={() =&gt; {}}
        buttonText="Submit"
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">List</span>&gt;</span>
        {reviews.map((review) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">ListItem</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{review.id}</span>&gt;</span>{review.body}<span class="hljs-tag">&lt;/<span class="hljs-name">ListItem</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">List</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Planet;
</code></pre>
<h2 id="heading-step-2-test-review-mutation"><strong>S</strong>tep <strong>2: T</strong>est review mutation</h2>
<p>We'll use a mutation to add new reviews. We test our mutation with GraphiQL in the Hasura console.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p3-s2-test-mutation-2.png" alt="Insert review mutation in GraphiQL" width="600" height="400" loading="lazy"></p>
<p>And convert it to accept variables so we can use it in our code.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p3-s2-variables-2.png" alt="Insert review mutation with variables" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-3-create-action"><strong>S</strong>tep <strong>3: C</strong>reate action</h2>
<p>The <a target="_blank" href="https://en.wikipedia.org/wiki/Bene_Gesserit">Bene Gesserit</a> have requested us to not allow (<em>cough</em> censor <em>cough</em>) the word "fear" in the reviews. We create an action for the business logic that will check for this word whenever a user submits a review.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p3-s3-derive-action-2.png" alt="&quot;Derive action&quot; button" width="600" height="400" loading="lazy"></p>
<p>Inside our freshly minted action, we go to the "Codegen" tab.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p3-s3-codegen-2.png" alt="&quot;Codegen&quot; tab" width="600" height="400" loading="lazy"></p>
<p>We select the nodejs-express option, and copy the handler boilerplate code below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p3-s3-express-2.png" alt="Boilerplate code for nodejs-express" width="600" height="400" loading="lazy"></p>
<p>We click "Try on Glitch," which takes us to a barebones express app, where we can paste our handler code.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p3-s3-glitch-2.png" alt="Pasting our handler code in Glitch" width="600" height="400" loading="lazy"></p>
<p>Back inside our action, we set our handler URL to the one from our Glitch app, with the correct route from our handler code.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p3-s3-handler-url-2.png" alt="Handler URL" width="600" height="400" loading="lazy"></p>
<p>We can now test our action in the console. It runs like a regular mutation, because we don't have any business logic checking for the word "fear" yet.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p3-s3-test-action-2.png" alt="Testing our action in the console" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-4-add-business-logic"><strong>S</strong>tep <strong>4: A</strong>dd business logic</h2>
<p>In our handler, we add business logic that checks for "fear" inside the body of the review. If it's fearless, we run the mutation as usual. If not, we return an ominous error.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p3-s4-biz-logic-3.png" alt="Business logic checking for &quot;fear&quot;" width="600" height="400" loading="lazy"></p>
<p>If we run the action with "fear" now, we get the error in the response:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p3-s4-error-2.png" alt="Testing our business logic in the console" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-5-order-reviews"><strong>S</strong>tep <strong>5: O</strong>rder reviews</h2>
<p>Our review order is currently topsy turvy. We add a <code>created_at</code> column to the <code>reviews</code> table so we can order by newest first.</p>
<pre><code class="lang-js">reviews(order_by: { <span class="hljs-attr">created_at</span>: desc })
</code></pre>
<h2 id="heading-step-6-add-review-mutation"><strong>S</strong>tep <strong>6: A</strong>dd review mutation</h2>
<p>Finally, we update our action syntax with variables, and copy paste it into our code as a mutation. We update our code to run this mutation when a user submits a new review, so that our business logic can check it for compliance (<em>ahem</em> obedience <em>ahem</em>) before updating our database.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useSubscription, useMutation, gql } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;
<span class="hljs-keyword">import</span> { List, ListItem } <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/List"</span>;
<span class="hljs-keyword">import</span> { Badge } <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/Badge"</span>;
<span class="hljs-keyword">import</span> InputForm <span class="hljs-keyword">from</span> <span class="hljs-string">"./shared/InputForm"</span>;

<span class="hljs-keyword">const</span> PLANET = gql<span class="hljs-string">`
  subscription Planet($id: uuid!) {
    planets_by_pk(id: $id) {
      id
      name
      cuisine
      reviews(order_by: { created_at: desc }) {
        id
        body
        created_at
      }
    }
  }
`</span>;

<span class="hljs-keyword">const</span> ADD_REVIEW = gql<span class="hljs-string">`
  mutation($body: String!, $id: uuid!) {
    AddFearlessReview(body: $body, id: $id) {
      affected_rows
    }
  }
`</span>;

<span class="hljs-keyword">const</span> Planet = <span class="hljs-function">(<span class="hljs-params">{
  match: {
    params: { id },
  },
}</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [inputVal, setInputVal] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> { loading, error, data } = useSubscription(PLANET, {
    <span class="hljs-attr">variables</span>: { id },
  });
  <span class="hljs-keyword">const</span> [addReview] = useMutation(ADD_REVIEW);

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading ...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error :(<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-keyword">const</span> { name, cuisine, reviews } = data.planets_by_pk;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
        {name} <span class="hljs-tag">&lt;<span class="hljs-name">Badge</span>&gt;</span>{cuisine}<span class="hljs-tag">&lt;/<span class="hljs-name">Badge</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">InputForm</span>
        <span class="hljs-attr">inputVal</span>=<span class="hljs-string">{inputVal}</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setInputVal(e.target.value)}
        onSubmit={() =&gt; {
          addReview({ variables: { id, body: inputVal } })
            .then(() =&gt; setInputVal(""))
            .catch((e) =&gt; {
              setInputVal(e.message);
            });
        }}
        buttonText="Submit"
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">List</span>&gt;</span>
        {reviews.map((review) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">ListItem</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{review.id}</span>&gt;</span>{review.body}<span class="hljs-tag">&lt;/<span class="hljs-name">ListItem</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">List</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Planet;
</code></pre>
<p>If we submit a new review that includes "fear" now, we get our ominous error, which we display in the input field.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/p3-s6-test-final-ui-2.png" alt="Testing our action via the UI" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-7-we-did-it">Step 7: We did it! ?</h2>
<p>Congrats on building a full-stack React &amp; GraphQL app!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/high-five.gif" alt="High five" width="600" height="400" loading="lazy"></p>
<h1 id="heading-what-does-the-future-hold">What does the future hold?</h1>
<p><img src="https://draftin.com/images/73049?token=kxAhFBHMt0pOLjXmaJQRIXSqFGtjWxb-WBuwPn2cjwPgL0mQP8TxoV4mqiQwXBotJ4cdCCRbehNabJMt2l9pvLA" alt="spice_must_flow.jpg" width="600" height="400" loading="lazy"></p>
<p>If only we had some spice melange, we would know. But we built so many features in so little time! We covered GraphQL queries, mutations, subscriptions, routing, searching, and even custom business logic with Hasura actions! I hope you had fun coding along.</p>
<p>What other features would you like to see in this app? Reach out to me on Twitter, and I'll make more tutorials! If you're inspired to add features yourself, please <a target="_blank" href="https://twitter.com/sez">do share</a> – I'd love to hear about them :)</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a TodoApp using ReactJS and Firebase ]]>
                </title>
                <description>
                    <![CDATA[ Hello folks, welcome to this tutorial. Before we begin you should be familiar with basic ReactJS concepts. If you're not, I would recommend that you go through the ReactJS documentation. We will use the following components in this application: Reac... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-todo-application-using-reactjs-and-firebase/</link>
                <guid isPermaLink="false">66d460f47df3a1f32ee7f897</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Firebase ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sharvin Shah ]]>
                </dc:creator>
                <pubDate>Wed, 15 Apr 2020 00:01:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/04/Screenshot-2020-04-11-at-5.10.03-PM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hello folks, welcome to this tutorial. Before we begin you should be familiar with basic ReactJS concepts. If you're not, I would recommend that you go through the <a target="_blank" href="https://reactjs.org/docs/getting-started.html">ReactJS documentation</a>.</p>
<p>We will use the following components in this application:</p>
<ol>
<li><p><a target="_blank" href="https://reactjs.org/"><strong>ReactJS</strong></a></p>
</li>
<li><p><a target="_blank" href="https://material-ui.com/"><strong>Material UI</strong></a></p>
</li>
<li><p><a target="_blank" href="https://firebase.google.com/"><strong>Firebase</strong></a></p>
</li>
<li><p><a target="_blank" href="https://expressjs.com/"><strong>ExpressJS</strong></a></p>
</li>
<li><p><a target="_blank" href="https://www.postman.com/"><strong>Postman</strong></a></p>
</li>
</ol>
<h2 id="heading-how-our-application-is-going-to-look">How our application is going to look:</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/Account-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Account creation</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/ezgif.com-optimize.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>TodoApp Dashboard</em></p>
<hr>
<h2 id="heading-application-architecture">Application Architecture:</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/TodoApp-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Application Architecture</em></p>
<h2 id="heading-understanding-our-components">Understanding our components:</h2>
<p>You may be wondering why we are using firebase in this application. Well, it provides secure <strong>Authentication</strong>, a <strong>Real-time database</strong>, a <strong>Serverless Component,</strong> and a <strong>Storage bucket</strong>.</p>
<p>We are using Express here so that we don't need to handle HTTP Exceptions. We are going to use all the firebase packages in our functions component. This is because we don't want to make our client application too big, which tends to slow the loading process of the UI.</p>
<p><strong>Note:</strong> I am going to divide this tutorial into four separate sections. At the start of every section, you will find a git commit that has the code developed in that section. Also If you want to see the complete code then it is available in this <a target="_blank" href="https://github.com/Sharvin26/TodoApp">repository</a>.</p>
<h2 id="heading-section-1-developing-todo-apis">Section 1: Developing Todo APIs</h2>
<p>In this section**,** we are going to develop these elements:</p>
<ol>
<li><p><strong>Configure the firebase functions.</strong></p>
</li>
<li><p><strong>Install the Express framework and build Todo APIs.</strong></p>
</li>
<li><p><strong>Configuring firestore as database.</strong></p>
</li>
</ol>
<p>The <strong>Todo API code</strong> implemented in this section can be found at this <a target="_blank" href="https://github.com/Sharvin26/TodoApp/tree/256e69f5d53646b648347b6f1fbdb965ad184763">commit</a>.</p>
<h3 id="heading-configure-firebase-functions">Configure Firebase Functions:</h3>
<p>Go to the <a target="_blank" href="https://firebase.google.com/">Firebase console</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/FirebaseFunctions.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Firebase Console</em></p>
<p>Select the <strong>Add Project</strong> option. After that follow the gif down below step by step to configure the firebase project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/FirebaseConfigure.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Firebase Configuration</em></p>
<p>Go to the functions tab and click on the <strong>Get Started</strong> button:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/FirebaseFunctionConfig1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Functions Dashboard</em></p>
<p>You will see a dialogue box which has instructions on <strong>How to set up the Firebase Functions</strong>. Go to your local environment. Open a command-line tool. To install the firebase tools in your machine use the command below:</p>
<pre><code class="lang-shell"> npm install -g firebase-tools
</code></pre>
<p>Once that is done then use the command <code>firebase init</code> to configure the firebase functions in your local environment. Select the following options when initialising the firebase function in the local environment:</p>
<ol>
<li><p>Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your choices =&gt; <em>Functions: Configure and deploy Cloud Functions</em></p>
</li>
<li><p>First, let’s associate this project directory with a Firebase project …. <em>\=&gt; Use an existing project</em></p>
</li>
<li><p>Select a default Firebase project for this directory =&gt; <em>application_name</em></p>
</li>
<li><p>What language would you like to use to write Cloud Functions? =&gt; <em>JavaScript</em></p>
</li>
<li><p>Do you want to use ESLint to catch probable bugs and enforce style? =&gt; <em>N</em></p>
</li>
<li><p>Do you want to install dependencies with npm now? (Y/n) =&gt; <em>Y</em></p>
</li>
</ol>
<p>After the configuration is done you will get the following message:</p>
<pre><code class="lang-shell">✔ Firebase initialization complete!
</code></pre>
<p>This will be our directory structure once the initialization is completed:</p>
<pre><code class="lang-shell">+-- firebase.json 
+-- functions
|   +-- index.js
|   +-- node_modules
|   +-- package-lock.json
|   +-- package.json
</code></pre>
<p>Now open the <code>index.js</code> under functions directory and copy-paste the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> functions = <span class="hljs-built_in">require</span>(<span class="hljs-string">'firebase-functions'</span>);

<span class="hljs-built_in">exports</span>.helloWorld = functions.https.onRequest(<span class="hljs-function">(<span class="hljs-params">request, response</span>) =&gt;</span> {
     response.send(<span class="hljs-string">"Hello from Firebase!"</span>);
});
</code></pre>
<p>Deploy the code to firebase functions using the following command:</p>
<pre><code class="lang-shell">firebase deploy
</code></pre>
<p>Once the deployment is done you will get the following logline at the end of your command line:</p>
<pre><code class="lang-shell">&gt; ✔  Deploy complete!
&gt; Project Console: https://console.firebase.google.com/project/todoapp-&lt;id&gt;/overview
</code></pre>
<p>Go to the <strong>Project Console &gt; Functions</strong> and there you will find the URL of the API. The URL will look like this:</p>
<pre><code class="lang-shell">https://&lt;hosting-region&gt;-todoapp-&lt;id&gt;.cloudfunctions.net/helloWorld
</code></pre>
<p>Copy this URL and paste it in the browser. You will get the following response:</p>
<pre><code class="lang-shell">Hello from Firebase!
</code></pre>
<p>This confirms that our Firebase function has been configured properly.</p>
<h3 id="heading-install-the-express-framework">Install the Express Framework:</h3>
<p>Now let’s install the <code>Express</code> framework in our project using the following command:</p>
<pre><code class="lang-shell">npm i express
</code></pre>
<p>Now let's create an <strong>APIs</strong> directory inside the <strong>functions</strong> directory. Inside that directory, we will create a file named <code>todos.js</code>. Remove everything from the <code>index.js</code> and then copy-paste the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">//index.js</span>

<span class="hljs-keyword">const</span> functions = <span class="hljs-built_in">require</span>(<span class="hljs-string">'firebase-functions'</span>);
<span class="hljs-keyword">const</span> app = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)();

<span class="hljs-keyword">const</span> {
    getAllTodos
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./APIs/todos'</span>)

app.get(<span class="hljs-string">'/todos'</span>, getAllTodos);
<span class="hljs-built_in">exports</span>.api = functions.https.onRequest(app);
</code></pre>
<p>We have assigned the getAllTodos function to the <strong>/todos</strong> route. So all the API calls on this route will execute via the getAllTodos function. Now go to the <code>todos.js</code> file under APIs directory and here we will write the getAllTodos function.</p>
<pre><code class="lang-js"><span class="hljs-comment">//todos.js</span>

<span class="hljs-built_in">exports</span>.getAllTodos = <span class="hljs-function">(<span class="hljs-params">request, response</span>) =&gt;</span> {
    todos = [
        {
            <span class="hljs-string">'id'</span>: <span class="hljs-string">'1'</span>,
            <span class="hljs-string">'title'</span>: <span class="hljs-string">'greeting'</span>,
            <span class="hljs-string">'body'</span>: <span class="hljs-string">'Hello world from sharvin shah'</span> 
        },
        {
            <span class="hljs-string">'id'</span>: <span class="hljs-string">'2'</span>,
            <span class="hljs-string">'title'</span>: <span class="hljs-string">'greeting2'</span>,
            <span class="hljs-string">'body'</span>: <span class="hljs-string">'Hello2 world2 from sharvin shah'</span> 
        }
    ]
    <span class="hljs-keyword">return</span> response.json(todos);
}
</code></pre>
<p>Here we have declared a sample JSON object. Later we will derive that from the Firestore. But for the time being we will return this. Now deploy this to your firebase function using the command <code>firebase deploy</code>. It will ask for permission to delete the module <strong>helloworld</strong> – just enter <strong>y</strong>.</p>
<pre><code class="lang-shell">The following functions are found in your project but do not exist in your local source code: helloWorld

Would you like to proceed with deletion? Selecting no will continue the rest of the deployments. (y/N) y
</code></pre>
<p>Once this is done go to the <strong>Project Console &gt; Functions</strong> and there you will find the URL of the API. The API will look like this:</p>
<pre><code class="lang-shell">https://&lt;hosting-region&gt;-todoapp-&lt;id&gt;.cloudfunctions.net/api
</code></pre>
<p>Now go to the browser and copy-paste the URL and add <strong>/todos</strong> at the end of this URL. You will get the following output:</p>
<pre><code class="lang-json">[
        {
            'id': '<span class="hljs-number">1</span>',
            'title': 'greeting',
            'body': 'Hello world from sharvin shah' 
        },
        {
            'id': '<span class="hljs-number">2</span>',
            'title': 'greeting2',
            'body': 'Hello2 world2 from sharvin shah' 
        }
]
</code></pre>
<h3 id="heading-firebase-firestore">Firebase Firestore:</h3>
<p>We will use a firebase firestore as a real-time database for our application. Now go to the <strong>Console &gt; Database</strong> in Firebase Console. To configure firestore follow the gif below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/Firestore.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Configuring Firestore</em></p>
<p>Once the configuration is done then click on the <strong>Start Collection</strong> button and set <strong>Collection ID</strong> as <strong>todos</strong>. Click Next and you will get the following popup:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/FireStore-collection.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating Database Manually</em></p>
<p>Ignore the DocumentID key. For the <strong>field, type, and value</strong>, refer to the JSON down below. Update the value accordingly:</p>
<pre><code class="lang-json">{
    Field: title,
    Type: String,
    Value: Hello World
},
{
    Field: body,
    Type: String,
    Value: Hello folks I hope you are staying home...
},
{
    Field: createtAt,
    type: timestamp,
    value: Add the current date and time here
}
</code></pre>
<p>Press the save button. You will see that the collection and the document is created. Go back to the local environment. We need to install <code>firebase-admin</code> which has the firestore package that we need. Use this command to install it:</p>
<pre><code class="lang-shell">npm i firebase-admin
</code></pre>
<p>Create a directory named <strong>util</strong> under the <strong>functions</strong> directory. Go to this directory and create a file name <code>admin.js</code>. In this file we will import the firebase admin package and initialize the firestore database object. We will export this so that other <strong>modules</strong> can use it.</p>
<pre><code class="lang-js"><span class="hljs-comment">//admin.js</span>

<span class="hljs-keyword">const</span> admin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'firebase-admin'</span>);

admin.initializeApp();

<span class="hljs-keyword">const</span> db = admin.firestore();

<span class="hljs-built_in">module</span>.exports = { admin, db };
</code></pre>
<p>Now let’s write an API to fetch this data. Go to the <code>todos.js</code> under the <strong>functions &gt; APIs</strong> directory. Remove the old code and copy-paste the code below:</p>
<pre><code class="lang-js"><span class="hljs-comment">//todos.js</span>

<span class="hljs-keyword">const</span> { db } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../util/admin'</span>);

<span class="hljs-built_in">exports</span>.getAllTodos = <span class="hljs-function">(<span class="hljs-params">request, response</span>) =&gt;</span> {
    db
        .collection(<span class="hljs-string">'todos'</span>)
        .orderBy(<span class="hljs-string">'createdAt'</span>, <span class="hljs-string">'desc'</span>)
        .get()
        .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
            <span class="hljs-keyword">let</span> todos = [];
            data.forEach(<span class="hljs-function">(<span class="hljs-params">doc</span>) =&gt;</span> {
                todos.push({
                    <span class="hljs-attr">todoId</span>: doc.id,
                    <span class="hljs-attr">title</span>: doc.data().title,
                    <span class="hljs-attr">body</span>: doc.data().body,
                    <span class="hljs-attr">createdAt</span>: doc.data().createdAt,
                });
            });
            <span class="hljs-keyword">return</span> response.json(todos);
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.error(err);
            <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: err.code});
        });
};
</code></pre>
<p>Here we are fetching all the todos from the database and forwarding them to the client in a list.</p>
<p>You can also run the application locally using <code>firebase serve</code> command instead of deploying it every time. When you run that command you may get an error regarding credentials. To fix it, follow the steps mentioned below:</p>
<ol>
<li><p>Go to the <strong>Project Settings</strong> (Settings icon at the top left-hand side)</p>
</li>
<li><p>Go to the <strong>service accounts tab</strong></p>
</li>
<li><p>Down there will be the option of <strong>Generating a new key</strong>. Click on that option and it will download a file with a JSON extension.</p>
</li>
<li><p>We need to export these credentials to our command line session. Use the command below to do that:</p>
</li>
</ol>
<pre><code class="lang-shell">export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/[FILE_NAME].json"
</code></pre>
<p>After that run firebase serve command. If you still get the error then use the following command: <code>firebase login --reauth</code>. It will open the Google sign-in page in a browser. Once sign-in is done then it will work without any error.</p>
<p>You will find a URL in the logs of your command-line tool when you run a firebase serve command. Open this URL in browser and append <code>/todos</code> after it.</p>
<pre><code class="lang-shell">✔ functions[api]: http function initialized (http://localhost:5000/todoapp-&lt;project-id&gt;/&lt;region-name&gt;/api).
</code></pre>
<p>You will get the following JSON output in your browser:</p>
<pre><code class="lang-json">[
    {
        <span class="hljs-attr">"todoId"</span>:<span class="hljs-string">"W67t1kSMO0lqvjCIGiuI"</span>,
        <span class="hljs-attr">"title"</span>:<span class="hljs-string">"Hello World"</span>,
        <span class="hljs-attr">"body"</span>:<span class="hljs-string">"Hello folks I hope you are staying home..."</span>,
        <span class="hljs-attr">"createdAt"</span>:{<span class="hljs-attr">"_seconds"</span>:<span class="hljs-number">1585420200</span>,<span class="hljs-attr">"_nanoseconds"</span>:<span class="hljs-number">0</span> }
    }
]
</code></pre>
<h3 id="heading-writing-other-apis">Writing Other APIs:</h3>
<p>It's time to write all the other todo APIs that we are going to require for our application.</p>
<ol>
<li><strong>Create Todo item:</strong> Go to the <code>index.js</code> under the functions directory. Import postOneTodo method under the existing getAllTodos. Also, assign the POST route to that method.</li>
</ol>
<pre><code class="lang-js"><span class="hljs-comment">//index.js</span>

<span class="hljs-keyword">const</span> {
    ..,
    postOneTodo
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./APIs/todos'</span>)

app.post(<span class="hljs-string">'/todo'</span>, postOneTodo);
</code></pre>
<p>Go to the <code>todos.js</code> inside the functions directory and add a new method <code>postOneTodo</code> under the existing <code>getAllTodos</code> method.</p>
<pre><code class="lang-js"><span class="hljs-comment">//todos.js</span>

<span class="hljs-built_in">exports</span>.postOneTodo = <span class="hljs-function">(<span class="hljs-params">request, response</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (request.body.body.trim() === <span class="hljs-string">''</span>) {
        <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">body</span>: <span class="hljs-string">'Must not be empty'</span> });
    }

    <span class="hljs-keyword">if</span>(request.body.title.trim() === <span class="hljs-string">''</span>) {
        <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">title</span>: <span class="hljs-string">'Must not be empty'</span> });
    }

    <span class="hljs-keyword">const</span> newTodoItem = {
        <span class="hljs-attr">title</span>: request.body.title,
        <span class="hljs-attr">body</span>: request.body.body,
        <span class="hljs-attr">createdAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString()
    }
    db
        .collection(<span class="hljs-string">'todos'</span>)
        .add(newTodoItem)
        .then(<span class="hljs-function">(<span class="hljs-params">doc</span>)=&gt;</span>{
            <span class="hljs-keyword">const</span> responseTodoItem = newTodoItem;
            responseTodoItem.id = doc.id;
            <span class="hljs-keyword">return</span> response.json(responseTodoItem);
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
            response.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">'Something went wrong'</span> });
            <span class="hljs-built_in">console</span>.error(err);
        });
};
</code></pre>
<p>In this method, we are adding a new Todo to our database. If the elements of our body are empty then we will return a response of 400 or else we will add the data.</p>
<p>Run the firebase serve command and open the postman application. Create a new request and select the method type as <strong>POST</strong>. Add the URL and a body of type JSON.</p>
<pre><code class="lang-shell">URL: http://localhost:5000/todoapp-&lt;app-id&gt;/&lt;region-name&gt;/api/todo

METHOD: POST

Body: {
   "title":"Hello World",
   "body": "We are writing this awesome API"
}
</code></pre>
<p>Press the send button and you will get the following response:</p>
<pre><code class="lang-json">{
     <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Hello World"</span>,
     <span class="hljs-attr">"body"</span>: <span class="hljs-string">"We are writing this awesome API"</span>,
     <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"2020-03-29T12:30:48.809Z"</span>,
     <span class="hljs-attr">"id"</span>: <span class="hljs-string">"nh41IgARCj8LPWBYzjU0"</span>
}
</code></pre>
<ol start="2">
<li><strong>Delete Todo item:</strong> Go to the <code>index.js</code> under the functions directory. Import the deleteTodo method under the existing postOneTodo. Also, assign the DELETE route to that method.</li>
</ol>
<pre><code class="lang-js"><span class="hljs-comment">//index.js</span>

<span class="hljs-keyword">const</span> {
    ..,
    deleteTodo
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./APIs/todos'</span>)

app.delete(<span class="hljs-string">'/todo/:todoId'</span>, deleteTodo);
</code></pre>
<p>Go to the <code>todos.js</code> and add a new method <code>deleteTodo</code> under the existing <code>postOneTodo</code> method.</p>
<pre><code class="lang-js"><span class="hljs-comment">//todos.js</span>

<span class="hljs-built_in">exports</span>.deleteTodo = <span class="hljs-function">(<span class="hljs-params">request, response</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> <span class="hljs-built_in">document</span> = db.doc(<span class="hljs-string">`/todos/<span class="hljs-subst">${request.params.todoId}</span>`</span>);
    <span class="hljs-built_in">document</span>
        .get()
        .then(<span class="hljs-function">(<span class="hljs-params">doc</span>) =&gt;</span> {
            <span class="hljs-keyword">if</span> (!doc.exists) {
                <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">404</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">'Todo not found'</span> })
            }
            <span class="hljs-keyword">return</span> <span class="hljs-built_in">document</span>.delete();
        })
        .then(<span class="hljs-function">() =&gt;</span> {
            response.json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Delete successfull'</span> });
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.error(err);
            <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: err.code });
        });
};
</code></pre>
<p>In this method, we are deleting a Todo from our database. Run the firebase serve command and go to the postman. Create a new request, select the method type as <strong>DELETE</strong> and add the URL.</p>
<pre><code class="lang-shell">URL: http://localhost:5000/todoapp-&lt;app-id&gt;/&lt;region-name&gt;/api/todo/&lt;todo-id&gt;

METHOD: DELETE
</code></pre>
<p>Press the send button and you will get the following response:</p>
<pre><code class="lang-json">{
   <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Delete successfull"</span>
}
</code></pre>
<ol start="3">
<li><strong>Edit Todo item:</strong> Go to the <code>index.js</code> under the functions directory. Import the editTodo method under the existing deleteTodo. Also, assign the PUT route to that method.</li>
</ol>
<pre><code class="lang-js"><span class="hljs-comment">//index.js</span>

<span class="hljs-keyword">const</span> {
    ..,
    editTodo
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./APIs/todos'</span>)

app.put(<span class="hljs-string">'/todo/:todoId'</span>, editTodo);
</code></pre>
<p>Go to the <code>todos.js</code> and add a new method <code>editTodo</code> under the existing <code>deleteTodo</code> method.</p>
<pre><code class="lang-js"><span class="hljs-comment">//todos.js</span>

<span class="hljs-built_in">exports</span>.editTodo = <span class="hljs-function">(<span class="hljs-params"> request, response </span>) =&gt;</span> { 
    <span class="hljs-keyword">if</span>(request.body.todoId || request.body.createdAt){
        response.status(<span class="hljs-number">403</span>).json({<span class="hljs-attr">message</span>: <span class="hljs-string">'Not allowed to edit'</span>});
    }
    <span class="hljs-keyword">let</span> <span class="hljs-built_in">document</span> = db.collection(<span class="hljs-string">'todos'</span>).doc(<span class="hljs-string">`<span class="hljs-subst">${request.params.todoId}</span>`</span>);
    <span class="hljs-built_in">document</span>.update(request.body)
    .then(<span class="hljs-function">()=&gt;</span> {
        response.json({<span class="hljs-attr">message</span>: <span class="hljs-string">'Updated successfully'</span>});
    })
    .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.error(err);
        <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">500</span>).json({ 
                <span class="hljs-attr">error</span>: err.code 
        });
    });
};
</code></pre>
<p>In this method, we are editing a Todo from our database. Remember here we are not allowing the user to edit the todoId or createdAt fields. Run the firebase serve command and go to the postman. Create a new request, select the method type as <strong>PUT,</strong> and add the URL.</p>
<pre><code class="lang-shell">URL: http://localhost:5000/todoapp-&lt;app-id&gt;/&lt;region-name&gt;/api/todo/&lt;todo-id&gt;

METHOD: PUT
</code></pre>
<p>Press the send button and you will get the following response:</p>
<pre><code class="lang-json">{  
   <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Updated successfully"</span>
}
</code></pre>
<p><strong>Directory structure till now:</strong></p>
<pre><code class="lang-shell">+-- firebase.json 
+-- functions
|   +-- API
|   +-- +-- todos.js
|   +-- util
|   +-- +-- admin.js
|   +-- index.js
|   +-- node_modules
|   +-- package-lock.json
|   +-- package.json
|   +-- .gitignore
</code></pre>
<p>With this, we have completed the first section of the application. You can go ahead have some coffee, take a break, and after that we will work on developing the User APIs.</p>
<h2 id="heading-section-2-developing-user-apis">Section 2: Developing User APIs</h2>
<p>In this section**,** we are going to develop these components:</p>
<ol>
<li><p><strong>User Authentication ( Login and Signup ) API.</strong></p>
</li>
<li><p><strong>GET and Update user details API.</strong></p>
</li>
<li><p><strong>Update the user profile picture API.</strong></p>
</li>
<li><p><strong>Securing the existing Todo API.</strong></p>
</li>
</ol>
<p>The User API code implemented in this section can be found at this <a target="_blank" href="https://github.com/Sharvin26/TodoApp/tree/951a8605d988b8e17bd1623eac5c46e449786d1b">commit</a>.</p>
<p>So let’s start building the User Authentication API. Go to the <strong>Firebase console &gt; Authentication.</strong></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/FirebaseAuthentication.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Firebase Authentication Page</em></p>
<p>Click on the <strong>Set up</strong> <strong>sign-in-method</strong> button. We will use email and password for user validation. Enable the <strong>Email/Password</strong> option.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/FirebaseAuth1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Firebase Set up Sign up page</em></p>
<p>Right now we will manually create our user. First, we will build the Login API. After that we will build the Sign-Up API.</p>
<p>Go to the Users Tab under Authentication, fill in the User details, and click on the <strong>Add User</strong> button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/Login.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Adding user manually</em></p>
<h3 id="heading-1-user-login-api">1. User Login API:</h3>
<p>First, we need to install the <code>firebase</code> package, which consists of the <strong>Firebase Authentication library,</strong> using the following command:</p>
<pre><code class="lang-shell">npm i firebase
</code></pre>
<p>Once the installation is done go to the <strong>functions &gt; APIs</strong> directory. Here we will create a <code>users.js</code> file. Now Inside <code>index.js</code> we import a loginUser method and assign the POST route to it.</p>
<pre><code class="lang-js"><span class="hljs-comment">//index.js</span>

<span class="hljs-keyword">const</span> {
    loginUser
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./APIs/users'</span>)

<span class="hljs-comment">// Users</span>
app.post(<span class="hljs-string">'/login'</span>, loginUser);
</code></pre>
<p>Go to the <strong>Project Settings &gt; General</strong> and there you will find the following card:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/app.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Getting Firebase configuration</em></p>
<p>Select the Web Icon and then follow the gif down below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/project.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Select the <strong>continue to console</strong> option. Once this is done you will see a JSON with firebase config. Go to the <strong>functions &gt; util</strong> directory and create a <code>config.js</code> file. Copy-paste the following code in this file:</p>
<pre><code class="lang-js"><span class="hljs-comment">// config.js</span>

<span class="hljs-built_in">module</span>.exports = {
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"............"</span>,
    <span class="hljs-attr">authDomain</span>: <span class="hljs-string">"........"</span>,
    <span class="hljs-attr">databaseURL</span>: <span class="hljs-string">"........"</span>,
    <span class="hljs-attr">projectId</span>: <span class="hljs-string">"......."</span>,
    <span class="hljs-attr">storageBucket</span>: <span class="hljs-string">"......."</span>,
    <span class="hljs-attr">messagingSenderId</span>: <span class="hljs-string">"........"</span>,
    <span class="hljs-attr">appId</span>: <span class="hljs-string">".........."</span>,
    <span class="hljs-attr">measurementId</span>: <span class="hljs-string">"......."</span>
};
</code></pre>
<p>Replace <code>............</code> with the values that you get under <strong>Firebase console &gt; Project settings &gt;</strong> <strong>General &gt; your apps &gt; Firebase SD snippet &gt; config</strong>.</p>
<p>Copy-paste the following code in the <code>users.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-comment">// users.js</span>

<span class="hljs-keyword">const</span> { admin, db } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../util/admin'</span>);
<span class="hljs-keyword">const</span> config = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../util/config'</span>);

<span class="hljs-keyword">const</span> firebase = <span class="hljs-built_in">require</span>(<span class="hljs-string">'firebase'</span>);

firebase.initializeApp(config);

<span class="hljs-keyword">const</span> { validateLoginData, validateSignUpData } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../util/validators'</span>);

<span class="hljs-comment">// Login</span>
<span class="hljs-built_in">exports</span>.loginUser = <span class="hljs-function">(<span class="hljs-params">request, response</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> user = {
        <span class="hljs-attr">email</span>: request.body.email,
        <span class="hljs-attr">password</span>: request.body.password
    }

    <span class="hljs-keyword">const</span> { valid, errors } = validateLoginData(user);
    <span class="hljs-keyword">if</span> (!valid) <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">400</span>).json(errors);

    firebase
        .auth()
        .signInWithEmailAndPassword(user.email, user.password)
        .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
            <span class="hljs-keyword">return</span> data.user.getIdToken();
        })
        .then(<span class="hljs-function">(<span class="hljs-params">token</span>) =&gt;</span> {
            <span class="hljs-keyword">return</span> response.json({ token });
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.error(error);
            <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">403</span>).json({ <span class="hljs-attr">general</span>: <span class="hljs-string">'wrong credentials, please try again'</span>});
        })
};
</code></pre>
<p>Here we are using a firebase <strong>signInWithEmailAndPassword</strong> module to check if the user-submitted credentials are right. If they are right then we send the token of that user or else a 403 status with a "wrong credentials" message.</p>
<p>Now let’s create <code>validators.js</code> under the <strong>functions &gt; util</strong> directory. Copy-paste the following code in this file:</p>
<pre><code class="lang-js"><span class="hljs-comment">// validators.js</span>

<span class="hljs-keyword">const</span> isEmpty = <span class="hljs-function">(<span class="hljs-params">string</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (string.trim() === <span class="hljs-string">''</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
};

<span class="hljs-built_in">exports</span>.validateLoginData = <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
   <span class="hljs-keyword">let</span> errors = {};
   <span class="hljs-keyword">if</span> (isEmpty(data.email)) errors.email = <span class="hljs-string">'Must not be empty'</span>;
   <span class="hljs-keyword">if</span> (isEmpty(data.password)) errors.password = <span class="hljs-string">'Must not be  empty'</span>;
   <span class="hljs-keyword">return</span> {
       errors,
       <span class="hljs-attr">valid</span>: <span class="hljs-built_in">Object</span>.keys(errors).length === <span class="hljs-number">0</span> ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span>
    };
};
</code></pre>
<p>With this our <strong>LoginAPI</strong> is completed. Run the <code>firebase serve</code> command and go to the postman. Create a new request, select the method type as <strong>POST</strong>, and add the URL and body.</p>
<pre><code class="lang-shell">URL: http://localhost:5000/todoapp-&lt;app-id&gt;/&lt;region-name&gt;/api/login

METHOD: POST

Body: {   
    "email":"Add email that is assigned for user in console", 
    "password": "Add password that is assigned for user in console"
}
</code></pre>
<p>Hit the send request button in postman and you will get the following output:</p>
<pre><code class="lang-json">{   
    <span class="hljs-attr">"token"</span>: <span class="hljs-string">".........."</span>
}
</code></pre>
<p>We will use this token in an upcoming part to <strong>get the user details</strong>. Remember this token expires in <strong>60 minutes</strong>. To generate a new token use this API again.</p>
<h3 id="heading-2-user-sign-up-api">2. User Sign-up API:</h3>
<p>The default authentication mechanism of firebase only allows you to store information like email, password, etc. But we need more information to identify if this user owns that todo so that they can perform read, update and delete operations on it.</p>
<p>To achieve this goal we are going to create a new collection called <strong>users</strong>. Under this collection, we will store the user’s data which will be mapped to the todo based on the username. Each username will be unique for all the users on the platform.</p>
<p>Go to the <code>index.js</code>. We import a signUpUser method and assign the POST route to it.</p>
<pre><code class="lang-js"><span class="hljs-comment">//index.js</span>

<span class="hljs-keyword">const</span> {
    ..,
    signUpUser
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./APIs/users'</span>)

app.post(<span class="hljs-string">'/signup'</span>, signUpUser);
</code></pre>
<p>Now go to the <code>validators.js</code> and add the following code below the <code>validateLoginData</code> method.</p>
<pre><code class="lang-js"><span class="hljs-comment">// validators.js</span>

<span class="hljs-keyword">const</span> isEmail = <span class="hljs-function">(<span class="hljs-params">email</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> emailRegEx = <span class="hljs-regexp">/^(([^&lt;&gt;()\[\]\\.,;:\s@"]+(\.[^&lt;&gt;()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/</span>;
    <span class="hljs-keyword">if</span> (email.match(emailRegEx)) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
};

<span class="hljs-built_in">exports</span>.validateSignUpData = <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
    <span class="hljs-keyword">let</span> errors = {};

    <span class="hljs-keyword">if</span> (isEmpty(data.email)) {
        errors.email = <span class="hljs-string">'Must not be empty'</span>;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (!isEmail(data.email)) {
        errors.email = <span class="hljs-string">'Must be valid email address'</span>;
    }

    <span class="hljs-keyword">if</span> (isEmpty(data.firstName)) errors.firstName = <span class="hljs-string">'Must not be empty'</span>;
    <span class="hljs-keyword">if</span> (isEmpty(data.lastName)) errors.lastName = <span class="hljs-string">'Must not be empty'</span>;
    <span class="hljs-keyword">if</span> (isEmpty(data.phoneNumber)) errors.phoneNumber = <span class="hljs-string">'Must not be empty'</span>;
    <span class="hljs-keyword">if</span> (isEmpty(data.country)) errors.country = <span class="hljs-string">'Must not be empty'</span>;

    <span class="hljs-keyword">if</span> (isEmpty(data.password)) errors.password = <span class="hljs-string">'Must not be empty'</span>;
    <span class="hljs-keyword">if</span> (data.password !== data.confirmPassword) errors.confirmPassword = <span class="hljs-string">'Passowrds must be the same'</span>;
    <span class="hljs-keyword">if</span> (isEmpty(data.username)) errors.username = <span class="hljs-string">'Must not be empty'</span>;

    <span class="hljs-keyword">return</span> {
        errors,
        <span class="hljs-attr">valid</span>: <span class="hljs-built_in">Object</span>.keys(errors).length === <span class="hljs-number">0</span> ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span>
    };
};
</code></pre>
<p>Now go to the <code>users.js</code> and add the following code below the <code>loginUser</code> module.</p>
<pre><code class="lang-js"><span class="hljs-comment">// users.js</span>

<span class="hljs-built_in">exports</span>.signUpUser = <span class="hljs-function">(<span class="hljs-params">request, response</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> newUser = {
        <span class="hljs-attr">firstName</span>: request.body.firstName,
        <span class="hljs-attr">lastName</span>: request.body.lastName,
        <span class="hljs-attr">email</span>: request.body.email,
        <span class="hljs-attr">phoneNumber</span>: request.body.phoneNumber,
        <span class="hljs-attr">country</span>: request.body.country,
        <span class="hljs-attr">password</span>: request.body.password,
        <span class="hljs-attr">confirmPassword</span>: request.body.confirmPassword,
        <span class="hljs-attr">username</span>: request.body.username
    };

    <span class="hljs-keyword">const</span> { valid, errors } = validateSignUpData(newUser);

    <span class="hljs-keyword">if</span> (!valid) <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">400</span>).json(errors);

    <span class="hljs-keyword">let</span> token, userId;
    db
        .doc(<span class="hljs-string">`/users/<span class="hljs-subst">${newUser.username}</span>`</span>)
        .get()
        .then(<span class="hljs-function">(<span class="hljs-params">doc</span>) =&gt;</span> {
            <span class="hljs-keyword">if</span> (doc.exists) {
                <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">username</span>: <span class="hljs-string">'this username is already taken'</span> });
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> firebase
                        .auth()
                        .createUserWithEmailAndPassword(
                            newUser.email, 
                            newUser.password
                    );
            }
        })
        .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
            userId = data.user.uid;
            <span class="hljs-keyword">return</span> data.user.getIdToken();
        })
        .then(<span class="hljs-function">(<span class="hljs-params">idtoken</span>) =&gt;</span> {
            token = idtoken;
            <span class="hljs-keyword">const</span> userCredentials = {
                <span class="hljs-attr">firstName</span>: newUser.firstName,
                <span class="hljs-attr">lastName</span>: newUser.lastName,
                <span class="hljs-attr">username</span>: newUser.username,
                <span class="hljs-attr">phoneNumber</span>: newUser.phoneNumber,
                <span class="hljs-attr">country</span>: newUser.country,
                <span class="hljs-attr">email</span>: newUser.email,
                <span class="hljs-attr">createdAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString(),
                userId
            };
            <span class="hljs-keyword">return</span> db
                    .doc(<span class="hljs-string">`/users/<span class="hljs-subst">${newUser.username}</span>`</span>)
                    .set(userCredentials);
        })
        .then(<span class="hljs-function">()=&gt;</span>{
            <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">201</span>).json({ token });
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.error(err);
            <span class="hljs-keyword">if</span> (err.code === <span class="hljs-string">'auth/email-already-in-use'</span>) {
                <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">email</span>: <span class="hljs-string">'Email already in use'</span> });
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">general</span>: <span class="hljs-string">'Something went wrong, please try again'</span> });
            }
        });
}
</code></pre>
<p>We validate our user data, and after that we send an email and password to the firebase <strong>createUserWithEmailAndPassword</strong> module to create the user. Once the user is created successfully we save the user credentials in the database.</p>
<p>With this our <strong>SignUp API</strong> is completed. Run the <code>firebase serve</code> command and go to the postman. Create a new request, select the method type as <strong>POST</strong>. Add the URL and body.</p>
<pre><code class="lang-shell">URL: http://localhost:5000/todoapp-&lt;app-id&gt;/&lt;region-name&gt;/api/signup

METHOD: POST

Body: {
   "firstName": "Add a firstName here",
   "lastName": "Add a lastName here",
   "email":"Add a email here",
   "phoneNumber": "Add a phone number here",
   "country": "Add a country here",
   "password": "Add a password here",
   "confirmPassword": "Add same password here",
   "username": "Add unique username here"
}
</code></pre>
<p>Hit the send request button in postman and you will get the following Output:</p>
<pre><code class="lang-json">{   
    <span class="hljs-attr">"token"</span>: <span class="hljs-string">".........."</span>
}
</code></pre>
<p>Now go to the <strong>Firebase console &gt; Database</strong> and there you will see the following output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/database.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see our user’s collection is successfully created with one document in it.</p>
<h3 id="heading-3-upload-user-profile-picture">3. Upload User Profile Picture:</h3>
<p>Our users will be able to upload their profile picture. To achieve this we will be using Storage bucket. Go to the <strong>Firebase console &gt; Storage</strong> and click on the <strong>Get started</strong> button. Follow the GIF below for the configuration:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/storage.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now go to the <strong>Rules</strong> tab under Storage and update the permission for the bucket access as per the image below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/storageRule.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>To upload the profile picture we will be using the package named <code>busboy</code>. To install this package, use the following command:</p>
<pre><code class="lang-shell">npm i busboy
</code></pre>
<p>Go to <code>index.js</code>. Import the uploadProfilePhoto method below the existing signUpUser method. Also assign the POST route to that method.</p>
<pre><code class="lang-js"><span class="hljs-comment">//index.js</span>

<span class="hljs-keyword">const</span> auth = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./util/auth'</span>);

<span class="hljs-keyword">const</span> {
    ..,
    uploadProfilePhoto
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./APIs/users'</span>)

app.post(<span class="hljs-string">'/user/image'</span>, auth, uploadProfilePhoto);
</code></pre>
<p>Here we have added an authentication layer so that only a user associated with that account can upload the image. Now create a file named <code>auth.js</code> in <strong>functions &gt; utils</strong> directory. Copy-paste the following code in that file:</p>
<pre><code class="lang-js"><span class="hljs-comment">// auth.js</span>

<span class="hljs-keyword">const</span> { admin, db } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./admin'</span>);

<span class="hljs-built_in">module</span>.exports = <span class="hljs-function">(<span class="hljs-params">request, response, next</span>) =&gt;</span> {
    <span class="hljs-keyword">let</span> idToken;
    <span class="hljs-keyword">if</span> (request.headers.authorization &amp;&amp; request.headers.authorization.startsWith(<span class="hljs-string">'Bearer '</span>)) {
        idToken = request.headers.authorization.split(<span class="hljs-string">'Bearer '</span>)[<span class="hljs-number">1</span>];
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'No token found'</span>);
        <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">403</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">'Unauthorized'</span> });
    }
    admin
        .auth()
        .verifyIdToken(idToken)
        .then(<span class="hljs-function">(<span class="hljs-params">decodedToken</span>) =&gt;</span> {
            request.user = decodedToken;
            <span class="hljs-keyword">return</span> db.collection(<span class="hljs-string">'users'</span>).where(<span class="hljs-string">'userId'</span>, <span class="hljs-string">'=='</span>, request.user.uid).limit(<span class="hljs-number">1</span>).get();
        })
        .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
            request.user.username = data.docs[<span class="hljs-number">0</span>].data().username;
            request.user.imageUrl = data.docs[<span class="hljs-number">0</span>].data().imageUrl;
            <span class="hljs-keyword">return</span> next();
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error while verifying token'</span>, err);
            <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">403</span>).json(err);
        });
};
</code></pre>
<p>Here we are using the firebase <strong>verifyIdToken</strong> module to verify the token. After that we are decoding the user details and passing them in the existing request.</p>
<p>Go to the <code>users.js</code> and add the following code below the <code>signup</code> method:</p>
<pre><code class="lang-js"><span class="hljs-comment">// users.js</span>

deleteImage = <span class="hljs-function">(<span class="hljs-params">imageName</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> bucket = admin.storage().bucket();
    <span class="hljs-keyword">const</span> path = <span class="hljs-string">`<span class="hljs-subst">${imageName}</span>`</span>
    <span class="hljs-keyword">return</span> bucket.file(path).delete()
    .then(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">return</span>
    })
    .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
        <span class="hljs-keyword">return</span>
    })
}

<span class="hljs-comment">// Upload profile picture</span>
<span class="hljs-built_in">exports</span>.uploadProfilePhoto = <span class="hljs-function">(<span class="hljs-params">request, response</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> BusBoy = <span class="hljs-built_in">require</span>(<span class="hljs-string">'busboy'</span>);
    <span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>);
    <span class="hljs-keyword">const</span> os = <span class="hljs-built_in">require</span>(<span class="hljs-string">'os'</span>);
    <span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);
    <span class="hljs-keyword">const</span> busboy = <span class="hljs-keyword">new</span> BusBoy({ <span class="hljs-attr">headers</span>: request.headers });

    <span class="hljs-keyword">let</span> imageFileName;
    <span class="hljs-keyword">let</span> imageToBeUploaded = {};

    busboy.on(<span class="hljs-string">'file'</span>, <span class="hljs-function">(<span class="hljs-params">fieldname, file, filename, encoding, mimetype</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (mimetype !== <span class="hljs-string">'image/png'</span> &amp;&amp; mimetype !== <span class="hljs-string">'image/jpeg'</span>) {
            <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">'Wrong file type submited'</span> });
        }
        <span class="hljs-keyword">const</span> imageExtension = filename.split(<span class="hljs-string">'.'</span>)[filename.split(<span class="hljs-string">'.'</span>).length - <span class="hljs-number">1</span>];
        imageFileName = <span class="hljs-string">`<span class="hljs-subst">${request.user.username}</span>.<span class="hljs-subst">${imageExtension}</span>`</span>;
        <span class="hljs-keyword">const</span> filePath = path.join(os.tmpdir(), imageFileName);
        imageToBeUploaded = { filePath, mimetype };
        file.pipe(fs.createWriteStream(filePath));
    });
    deleteImage(imageFileName);
    busboy.on(<span class="hljs-string">'finish'</span>, <span class="hljs-function">() =&gt;</span> {
        admin
            .storage()
            .bucket()
            .upload(imageToBeUploaded.filePath, {
                <span class="hljs-attr">resumable</span>: <span class="hljs-literal">false</span>,
                <span class="hljs-attr">metadata</span>: {
                    <span class="hljs-attr">metadata</span>: {
                        <span class="hljs-attr">contentType</span>: imageToBeUploaded.mimetype
                    }
                }
            })
            .then(<span class="hljs-function">() =&gt;</span> {
                <span class="hljs-keyword">const</span> imageUrl = <span class="hljs-string">`https://firebasestorage.googleapis.com/v0/b/<span class="hljs-subst">${config.storageBucket}</span>/o/<span class="hljs-subst">${imageFileName}</span>?alt=media`</span>;
                <span class="hljs-keyword">return</span> db.doc(<span class="hljs-string">`/users/<span class="hljs-subst">${request.user.username}</span>`</span>).update({
                    imageUrl
                });
            })
            .then(<span class="hljs-function">() =&gt;</span> {
                <span class="hljs-keyword">return</span> response.json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Image uploaded successfully'</span> });
            })
            .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
                <span class="hljs-built_in">console</span>.error(error);
                <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: error.code });
            });
    });
    busboy.end(request.rawBody);
};
</code></pre>
<p>With this our <strong>Upload Profile Picture API</strong> is completed. Run the <code>firebase serve</code> command and go to the postman. Create a new request, select the method type as <strong>POST</strong>, add the URL, and in the body section select type as form-data.</p>
<p>The request is protected so you’ll need to send the <strong>bearer token</strong> also. To send the bearer token, log in again if the token has expired. After that in <strong>Postman App &gt; Authorization tab &gt; Type &gt; Bearer Token</strong> and in the token section paste the token.</p>
<pre><code class="lang-shell">URL: http://localhost:5000/todoapp-&lt;app-id&gt;/&lt;region-name&gt;/api/user/image

METHOD: GET

Body: { REFER THE IMAGE down below }
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/cover.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Hit the send request button in postman and you will get the following Output:</p>
<pre><code class="lang-json">{        
    <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Image uploaded successfully"</span>
}
</code></pre>
<h3 id="heading-4-get-user-details">4. Get User Details:</h3>
<p>Here we are fetching the data of our user from the database. Go to the <code>index.js</code> and import the getUserDetail method and assign GET route to it.</p>
<pre><code class="lang-js"><span class="hljs-comment">// index.js</span>

<span class="hljs-keyword">const</span> {
    ..,
    getUserDetail
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./APIs/users'</span>)

app.get(<span class="hljs-string">'/user'</span>, auth, getUserDetail);
</code></pre>
<p>Now go to the <code>users.js</code> and add the following code after the <code>uploadProfilePhoto</code> module:</p>
<pre><code class="lang-js"><span class="hljs-comment">// users.js</span>

<span class="hljs-built_in">exports</span>.getUserDetail = <span class="hljs-function">(<span class="hljs-params">request, response</span>) =&gt;</span> {
    <span class="hljs-keyword">let</span> userData = {};
    db
        .doc(<span class="hljs-string">`/users/<span class="hljs-subst">${request.user.username}</span>`</span>)
        .get()
        .then(<span class="hljs-function">(<span class="hljs-params">doc</span>) =&gt;</span> {
            <span class="hljs-keyword">if</span> (doc.exists) {
                userData.userCredentials = doc.data();
                <span class="hljs-keyword">return</span> response.json(userData);
            }    
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.error(error);
            <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: error.code });
        });
}
</code></pre>
<p>We are using the firebase <strong>doc().get()</strong> module to derive the user details. With this our <strong>GET User Details API</strong> is completed. Run the <code>firebase serve</code> command and go to the postman. Create a new request, select the method type: <strong>GET</strong>, and add the URL and body.</p>
<p>The request is protected so you’ll need to send the <strong>bearer token</strong> also. To send the bearer token, log in again if the token has expired.</p>
<pre><code class="lang-shell">URL: http://localhost:5000/todoapp-&lt;app-id&gt;/&lt;region-name&gt;/api/user
METHOD: GET
</code></pre>
<p>Hit the send request button in postman and you will get the following Output:</p>
<pre><code class="lang-json">{
   <span class="hljs-attr">"userCredentials"</span>: {
       <span class="hljs-attr">"phoneNumber"</span>: <span class="hljs-string">"........"</span>,
       <span class="hljs-attr">"email"</span>: <span class="hljs-string">"........"</span>,
       <span class="hljs-attr">"country"</span>: <span class="hljs-string">"........"</span>,
       <span class="hljs-attr">"userId"</span>: <span class="hljs-string">"........"</span>,
       <span class="hljs-attr">"username"</span>: <span class="hljs-string">"........"</span>,
       <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"........"</span>,
       <span class="hljs-attr">"lastName"</span>: <span class="hljs-string">"........"</span>,
       <span class="hljs-attr">"firstName"</span>: <span class="hljs-string">"........"</span>
    }
}
</code></pre>
<h3 id="heading-5-update-user-details">5. Update user details:</h3>
<p>Now let’s add the functionality to update the user details. Go to the <code>index.js</code> and copy-paste the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">// index.js</span>

<span class="hljs-keyword">const</span> {
    ..,
    updateUserDetails
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./APIs/users'</span>)

app.post(<span class="hljs-string">'/user'</span>, auth, updateUserDetails);
</code></pre>
<p>Now go to the <code>users.js</code> and add the <code>updateUserDetails</code> module below the existing <code>getUserDetails</code> :</p>
<pre><code class="lang-js"><span class="hljs-comment">// users.js</span>

<span class="hljs-built_in">exports</span>.updateUserDetails = <span class="hljs-function">(<span class="hljs-params">request, response</span>) =&gt;</span> {
    <span class="hljs-keyword">let</span> <span class="hljs-built_in">document</span> = db.collection(<span class="hljs-string">'users'</span>).doc(<span class="hljs-string">`<span class="hljs-subst">${request.user.username}</span>`</span>);
    <span class="hljs-built_in">document</span>.update(request.body)
    .then(<span class="hljs-function">()=&gt;</span> {
        response.json({<span class="hljs-attr">message</span>: <span class="hljs-string">'Updated successfully'</span>});
    })
    .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.error(error);
        <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">500</span>).json({ 
            <span class="hljs-attr">message</span>: <span class="hljs-string">"Cannot Update the value"</span>
        });
    });
}
</code></pre>
<p>Here we are using the firebase <strong>update</strong> method. With this our <strong>Update User Details API</strong> is completed. Follow the same procedure for a request as with the Get User Details API above with one change. Add body in the request here and method as POST.</p>
<pre><code class="lang-shell">URL: http://localhost:5000/todoapp-&lt;app-id&gt;/&lt;region-name&gt;/api/user

METHOD: POST

Body : {
    // You can edit First Name, last Name and country
    // We will disable other Form Tags from our UI
}
</code></pre>
<p>Hit the send request button in postman and you will get the following Output:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Updated successfully"</span>
}
</code></pre>
<h3 id="heading-6-securing-todo-apis">6. Securing Todo APIs:</h3>
<p>To secure the Todo API so that only the chosen user can access it, we will make a few changes in our existing code. Firstly, we will update our <code>index.js</code> as follows:</p>
<pre><code class="lang-js"><span class="hljs-comment">// index.js</span>

<span class="hljs-comment">// Todos</span>
app.get(<span class="hljs-string">'/todos'</span>, auth, getAllTodos);
app.get(<span class="hljs-string">'/todo/:todoId'</span>, auth, getOneTodo);
app.post(<span class="hljs-string">'/todo'</span>,auth, postOneTodo);
app.delete(<span class="hljs-string">'/todo/:todoId'</span>,auth, deleteTodo);
app.put(<span class="hljs-string">'/todo/:todoId'</span>,auth, editTodo);
</code></pre>
<p>We have updated all the <strong>Todo routes</strong> by adding <code>auth</code> so that all the API calls will require a token and can only be accessed by the particular user.</p>
<p>After that go to the <code>todos.js</code> under the <strong>functions &gt; APIs</strong> directory.</p>
<ol>
<li><strong>Create Todo API:</strong> Open the <code>todos.js</code> and under the <strong>postOneTodo</strong> method add the username key as follows:</li>
</ol>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> newTodoItem = {
     ..,
     <span class="hljs-attr">username</span>: request.user.username,
     ..
}
</code></pre>
<ol start="2">
<li><strong>GET All Todos API:</strong> Open the <code>todos.js</code> and under the <strong>getAllTodos</strong> method add the where clause as follows:</li>
</ol>
<pre><code class="lang-js">db
.collection(<span class="hljs-string">'todos'</span>)
.where(<span class="hljs-string">'username'</span>, <span class="hljs-string">'=='</span>, request.user.username)
.orderBy(<span class="hljs-string">'createdAt'</span>, <span class="hljs-string">'desc'</span>)
</code></pre>
<p>Run the firebase serve and test our GET API. <strong>Don’t forget to send the bearer token.</strong> Here you will get a response error as follows:</p>
<pre><code class="lang-json">{   
    <span class="hljs-attr">"error"</span>: <span class="hljs-number">9</span>
}
</code></pre>
<p>Go to the command line and you will see the following lines logged:</p>
<pre><code class="lang-shell">i  functions: Beginning execution of "api"&gt;  Error: 9 FAILED_PRECONDITION: The query requires an index. You can create it here: &lt;URL&gt;&gt;      at callErrorFromStatus
</code></pre>
<p>Open this in the browser and click on create index.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/index.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Once the index is built send the request again and you will get the following output:</p>
<pre><code class="lang-json">[
   {
      <span class="hljs-attr">"todoId"</span>: <span class="hljs-string">"......"</span>,
      <span class="hljs-attr">"title"</span>: <span class="hljs-string">"......"</span>,
      <span class="hljs-attr">"username"</span>: <span class="hljs-string">"......"</span>,
      <span class="hljs-attr">"body"</span>: <span class="hljs-string">"......"</span>,
      <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"2020-03-30T13:01:58.478Z"</span>
   }
]
</code></pre>
<ol start="3">
<li><strong>Delete Todo API:</strong> Open the <code>todos.js</code> and under the <strong>deleteTodo</strong> method add the following condition. Add this condition inside the <strong>document.get().then()</strong> query below the <strong>!doc.exists</strong> condition.</li>
</ol>
<pre><code class="lang-js">..
if(doc.data().username !== request.user.username){
     <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">403</span>).json({<span class="hljs-attr">error</span>:<span class="hljs-string">"UnAuthorized"</span>})
}
</code></pre>
<h3 id="heading-directory-structure-up-to-now">Directory structure up to now:</h3>
<pre><code class="lang-shell">+-- firebase.json 
+-- functions
|   +-- API
|   +-- +-- todos.js 
|   +-- +-- users.js
|   +-- util
|   +-- +-- admin.js
|   +-- +-- auth.js
|   +-- +-- validators.js
|   +-- index.js
|   +-- node_modules
|   +-- package-lock.json
|   +-- package.json
|   +-- .gitignore
</code></pre>
<p>With this we have completed our API backend. Take a break, have a coffee, and after that we will start building the front end of our application</p>
<h2 id="heading-section-3-user-dashboard">Section 3: User Dashboard</h2>
<p>In this section**,** we are going to develop these components:</p>
<ol>
<li><p><strong>Configure ReactJS and Material UI.</strong></p>
</li>
<li><p><strong>Building Login and SignUp Form.</strong></p>
</li>
<li><p><strong>Building Account Section.</strong></p>
</li>
</ol>
<p>The User Dashboard code implemented in this section can be found at this <a target="_blank" href="https://github.com/Sharvin26/TodoApp/tree/2b207786651167c1ed5327c2c8583e97080abb54/view">commit</a>.</p>
<h3 id="heading-1-configure-reactjs-and-material-ui">1. Configure ReactJS and Material UI:</h3>
<p>We will use the create-react-app template. It gives us a fundamental structure for developing the application. To install it, use the following command:</p>
<pre><code class="lang-shell">npm install -g create-react-app
</code></pre>
<p>Go to the root folder of the project where the functions directory is present. Initialize our front end application using the following command:</p>
<pre><code class="lang-shell">create-react-app view
</code></pre>
<p>Remember to use version <strong>v16.13.1</strong> of the ReactJS library_._</p>
<p>Once the installation is completed then you'll see the following in your command line logs:</p>
<pre><code class="lang-shell">cd view
  npm start
Happy hacking!
</code></pre>
<p>With this, we have configured our React application. You’ll get the following directory structure:</p>
<pre><code class="lang-shell">+-- firebase.json 
+-- functions { This Directory consists our API logic }
+-- view { This Directory consists our FrontEnd Compoenents }
+-- .firebaserc
+-- .gitignore
</code></pre>
<p>Now run the application using the command <code>npm start</code> . Go to the browser on <code>[http://localhost:3000/](http://localhost:3000/)</code> and you’ll see the following output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/React1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now we will remove all the unnecessary components. Go to the view directory and then remove all the files which have <strong>[ Remove ]</strong> in front of them. <strong>For this, refer to the directory tree structure below.</strong></p>
<pre><code class="lang-shell">+-- README.md [ Remove ]
+-- package-lock.json
+-- package.json
+-- node_modules
+-- .gitignore
+-- public
|   +-- favicon.ico [ Remove ]
|   +-- index.html
|   +-- logo192.png [ Remove ]
|   +-- logo512.png [ Remove ]
|   +-- manifest.json
|   +-- robots.txt
+-- src
|   +-- App.css
|   +-- App.test.js
|   +-- index.js
|   +-- serviceWorker.js
|   +-- App.js
|   +-- index.css [ Remove ]
|   +-- logo.svg [ Remove ]
|   +-- setupTests.js
</code></pre>
<p>Go to <code>index.html</code> under the public directory and remove the following lines:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"%PUBLIC_URL%/favicon.ico"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"apple-touch-icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"%PUBLIC_URL%/logo192.png"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"manifest"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"%PUBLIC_URL%/manifest.json"</span> /&gt;</span>
</code></pre>
<p>Now go to the <code>App.js</code> under the src directory and replace the old code with the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Go to the <code>index.js</code> and remove the following import:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>
</code></pre>
<p>I have not deleted the <code>App.css</code> nor I am using it in this application. But if you want to delete or use it you are free to do that.</p>
<p>Go to the browser on <code>[http://localhost:3000/](http://localhost:3000/)</code> and you’ll get a blank screen output.</p>
<p>To install Material UI go to the view directory and copy-paste this command in the terminal:</p>
<pre><code class="lang-shell">npm install @material-ui/core
</code></pre>
<p>Remember to use version <strong>v4.9.8</strong> of the Material UI library.</p>
<h3 id="heading-2-login-form">2. Login Form:</h3>
<p>To develop the login form go to <code>App.js</code>. At the top of <code>App.js</code> add the following imports:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { BrowserRouter <span class="hljs-keyword">as</span> Router, Route, Switch } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
<span class="hljs-keyword">import</span> login <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/login'</span>;
</code></pre>
<p>We are using <strong>Switch</strong> and <strong>Route</strong> to assign routes for our TodoApp. Right now we will add only the <strong>/login</strong> route and assign a login component to it.</p>
<pre><code class="lang-html">// App.js

<span class="hljs-tag">&lt;<span class="hljs-name">Router</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">Switch</span>&gt;</span>
           <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">exact</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/login"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{login}/</span>&gt;</span>
       <span class="hljs-tag">&lt;/<span class="hljs-name">Switch</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">Router</span>&gt;</span>
</code></pre>
<p>Create a <strong>pages</strong> directory under the existing <strong>view</strong> directory and a file named <code>login.js</code> under the <strong>pages</strong> directory.</p>
<p>We will import Material UI components and the Axios package in the <code>login.js</code>:</p>
<pre><code class="lang-js"><span class="hljs-comment">// login.js</span>

<span class="hljs-comment">// Material UI components</span>
<span class="hljs-keyword">import</span> React, { Component } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> Avatar <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Avatar'</span>;
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Button'</span>;
<span class="hljs-keyword">import</span> CssBaseline <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/CssBaseline'</span>;
<span class="hljs-keyword">import</span> TextField <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/TextField'</span>;
<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Link'</span>;
<span class="hljs-keyword">import</span> Grid <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Grid'</span>;
<span class="hljs-keyword">import</span> LockOutlinedIcon <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/icons/LockOutlined'</span>;
<span class="hljs-keyword">import</span> Typography <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Typography'</span>;
<span class="hljs-keyword">import</span> withStyles <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/styles/withStyles'</span>;
<span class="hljs-keyword">import</span> Container <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Container'</span>;
<span class="hljs-keyword">import</span> CircularProgress <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/CircularProgress'</span>;

<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
</code></pre>
<p>We will add the following styles to our login page:</p>
<pre><code class="lang-js"><span class="hljs-comment">// login.js</span>

<span class="hljs-keyword">const</span> styles = <span class="hljs-function">(<span class="hljs-params">theme</span>) =&gt;</span> ({
    <span class="hljs-attr">paper</span>: {
        <span class="hljs-attr">marginTop</span>: theme.spacing(<span class="hljs-number">8</span>),
        <span class="hljs-attr">display</span>: <span class="hljs-string">'flex'</span>,
        <span class="hljs-attr">flexDirection</span>: <span class="hljs-string">'column'</span>,
        <span class="hljs-attr">alignItems</span>: <span class="hljs-string">'center'</span>
    },
    <span class="hljs-attr">avatar</span>: {
        <span class="hljs-attr">margin</span>: theme.spacing(<span class="hljs-number">1</span>),
        <span class="hljs-attr">backgroundColor</span>: theme.palette.secondary.main
    },
    <span class="hljs-attr">form</span>: {
        <span class="hljs-attr">width</span>: <span class="hljs-string">'100%'</span>,
        <span class="hljs-attr">marginTop</span>: theme.spacing(<span class="hljs-number">1</span>)
    },
    <span class="hljs-attr">submit</span>: {
        <span class="hljs-attr">margin</span>: theme.spacing(<span class="hljs-number">3</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>)
    },
    <span class="hljs-attr">customError</span>: {
        <span class="hljs-attr">color</span>: <span class="hljs-string">'red'</span>,
        <span class="hljs-attr">fontSize</span>: <span class="hljs-string">'0.8rem'</span>,
        <span class="hljs-attr">marginTop</span>: <span class="hljs-number">10</span>
    },
    <span class="hljs-attr">progess</span>: {
        <span class="hljs-attr">position</span>: <span class="hljs-string">'absolute'</span>
    }
});
</code></pre>
<p>We will create a class named login which has a form and submit handler inside it.</p>
<pre><code class="lang-js"><span class="hljs-comment">// login.js</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">login</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span> </span>{
    <span class="hljs-keyword">constructor</span>(props) {
        <span class="hljs-built_in">super</span>(props);

        <span class="hljs-built_in">this</span>.state = {
            <span class="hljs-attr">email</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">password</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">errors</span>: [],
            <span class="hljs-attr">loading</span>: <span class="hljs-literal">false</span>
        };
    }

    componentWillReceiveProps(nextProps) {
        <span class="hljs-keyword">if</span> (nextProps.UI.errors) {
            <span class="hljs-built_in">this</span>.setState({
                <span class="hljs-attr">errors</span>: nextProps.UI.errors
            });
        }
    }

    handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        <span class="hljs-built_in">this</span>.setState({
            [event.target.name]: event.target.value
        });
    };

    handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        event.preventDefault();
        <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">loading</span>: <span class="hljs-literal">true</span> });
        <span class="hljs-keyword">const</span> userData = {
            <span class="hljs-attr">email</span>: <span class="hljs-built_in">this</span>.state.email,
            <span class="hljs-attr">password</span>: <span class="hljs-built_in">this</span>.state.password
        };
        axios
            .post(<span class="hljs-string">'/login'</span>, userData)
            .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
                <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'AuthToken'</span>, <span class="hljs-string">`Bearer <span class="hljs-subst">${response.data.token}</span>`</span>);
                <span class="hljs-built_in">this</span>.setState({ 
                    <span class="hljs-attr">loading</span>: <span class="hljs-literal">false</span>,
                });        
                <span class="hljs-built_in">this</span>.props.history.push(<span class="hljs-string">'/'</span>);
            })
            .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {                
                <span class="hljs-built_in">this</span>.setState({
                    <span class="hljs-attr">errors</span>: error.response.data,
                    <span class="hljs-attr">loading</span>: <span class="hljs-literal">false</span>
                });
            });
    };

    render() {
        <span class="hljs-keyword">const</span> { classes } = <span class="hljs-built_in">this</span>.props;
        <span class="hljs-keyword">const</span> { errors, loading } = <span class="hljs-built_in">this</span>.state;
        <span class="hljs-keyword">return</span> (
            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">component</span>=<span class="hljs-string">"main"</span> <span class="hljs-attr">maxWidth</span>=<span class="hljs-string">"xs"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">CssBaseline</span> /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.paper}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Avatar</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.avatar}</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">LockOutlinedIcon</span> /&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Avatar</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">component</span>=<span class="hljs-string">"h1"</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"h5"</span>&gt;</span>
                        Login
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.form}</span> <span class="hljs-attr">noValidate</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                            <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                            <span class="hljs-attr">margin</span>=<span class="hljs-string">"normal"</span>
                            <span class="hljs-attr">required</span>
                            <span class="hljs-attr">fullWidth</span>
                            <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span>
                            <span class="hljs-attr">label</span>=<span class="hljs-string">"Email Address"</span>
                            <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span>
                            <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"email"</span>
                            <span class="hljs-attr">autoFocus</span>
                            <span class="hljs-attr">helperText</span>=<span class="hljs-string">{errors.email}</span>
                            <span class="hljs-attr">error</span>=<span class="hljs-string">{errors.email</span> ? <span class="hljs-attr">true</span> <span class="hljs-attr">:</span> <span class="hljs-attr">false</span>}
                            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                        /&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                            <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                            <span class="hljs-attr">margin</span>=<span class="hljs-string">"normal"</span>
                            <span class="hljs-attr">required</span>
                            <span class="hljs-attr">fullWidth</span>
                            <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span>
                            <span class="hljs-attr">label</span>=<span class="hljs-string">"Password"</span>
                            <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
                            <span class="hljs-attr">id</span>=<span class="hljs-string">"password"</span>
                            <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"current-password"</span>
                            <span class="hljs-attr">helperText</span>=<span class="hljs-string">{errors.password}</span>
                            <span class="hljs-attr">error</span>=<span class="hljs-string">{errors.password</span> ? <span class="hljs-attr">true</span> <span class="hljs-attr">:</span> <span class="hljs-attr">false</span>}
                            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                        /&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
                            <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
                            <span class="hljs-attr">fullWidth</span>
                            <span class="hljs-attr">variant</span>=<span class="hljs-string">"contained"</span>
                            <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span>
                            <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.submit}</span>
                            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{this.handleSubmit}</span>
                            <span class="hljs-attr">disabled</span>=<span class="hljs-string">{loading</span> || !<span class="hljs-attr">this.state.email</span> || !<span class="hljs-attr">this.state.password</span>}
                        &gt;</span>
                            Sign In
                            {loading &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">CircularProgress</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{30}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.progess}</span> /&gt;</span>}
                        <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">container</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"signup"</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"body2"</span>&gt;</span>
                                    {"Don't have an account? Sign Up"}
                                <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                        {errors.general &amp;&amp; (
                            <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"body2"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.customError}</span>&gt;</span>
                                {errors.general}
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
                        )}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span></span>
        );
    }
}
</code></pre>
<p>At the end of this file add the following export:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> withStyles(styles)(login);
</code></pre>
<p>Add our firebase functions URL to <strong>view &gt; package.json</strong> as follows:</p>
<blockquote>
<p>Remember: Add a key named <strong>proxy</strong> below the existing browserslist JSON object</p>
</blockquote>
<pre><code class="lang-json"><span class="hljs-string">"proxy"</span>: <span class="hljs-string">"https://&lt;region-name&gt;-todoapp-&lt;id&gt;.cloudfunctions.net/api"</span>
</code></pre>
<p>Install the <strong>Axios</strong> and <strong>material icon</strong> package using the following commands:</p>
<pre><code class="lang-shell">// Axios command:
npm i axios
// Material Icons:
npm install @material-ui/icons
</code></pre>
<p>We have added a login route in <code>App.js</code>. In the <code>login.js</code> we have created a class component that handles the state, sends the post request to the login API using the Axios package. If the request is successful then we store the token. If we get errors in the response we simply render them on the UI.</p>
<p>Go to the browser at <code>[http://localhost:3000/login](http://localhost:3000/login)</code> and you’ll see the following Login UI.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/LoginPage.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Login Page</em></p>
<p>Try filling wrong credentials or sending an empty request and you will get the errors. Send a valid request. Go to the <strong>Developer console &gt; Application</strong>. You will see that users token is store in the Local storage. Once the Login is successful we will be routed back to the Home page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/loginDev.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Google Chrome Developer Console</em></p>
<h3 id="heading-3-signup-form">3. Signup Form:</h3>
<p>To develop the Signup form go to <code>App.js</code> and update the existing <code>Route</code> component with the line below:</p>
<pre><code class="lang-js"><span class="hljs-comment">// App.js</span>

&lt;Route exact path=<span class="hljs-string">"/signup"</span> component={signup}/&gt;
</code></pre>
<p>Don’t forget to import:</p>
<pre><code class="lang-js"><span class="hljs-comment">// App.js</span>

<span class="hljs-keyword">import</span> signup <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/signup'</span>;
</code></pre>
<p>Create a file named <code>signup.js</code> under the <strong>pages directory</strong>.</p>
<p>Inside the signup.js we will import the Material UI and Axios package:</p>
<pre><code class="lang-js"><span class="hljs-comment">// signup.js</span>

<span class="hljs-keyword">import</span> React, { Component } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> Avatar <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Avatar'</span>;
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Button'</span>;
<span class="hljs-keyword">import</span> CssBaseline <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/CssBaseline'</span>;
<span class="hljs-keyword">import</span> TextField <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/TextField'</span>;
<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Link'</span>;
<span class="hljs-keyword">import</span> Grid <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Grid'</span>;
<span class="hljs-keyword">import</span> LockOutlinedIcon <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/icons/LockOutlined'</span>;
<span class="hljs-keyword">import</span> Typography <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Typography'</span>;
<span class="hljs-keyword">import</span> Container <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Container'</span>;
<span class="hljs-keyword">import</span> withStyles <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/styles/withStyles'</span>;
<span class="hljs-keyword">import</span> CircularProgress <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/CircularProgress'</span>;

<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
</code></pre>
<p>We will add the following styles to our signup page:</p>
<pre><code class="lang-js"><span class="hljs-comment">// signup.js</span>


<span class="hljs-keyword">const</span> styles = <span class="hljs-function">(<span class="hljs-params">theme</span>) =&gt;</span> ({
    <span class="hljs-attr">paper</span>: {
        <span class="hljs-attr">marginTop</span>: theme.spacing(<span class="hljs-number">8</span>),
        <span class="hljs-attr">display</span>: <span class="hljs-string">'flex'</span>,
        <span class="hljs-attr">flexDirection</span>: <span class="hljs-string">'column'</span>,
        <span class="hljs-attr">alignItems</span>: <span class="hljs-string">'center'</span>
    },
    <span class="hljs-attr">avatar</span>: {
        <span class="hljs-attr">margin</span>: theme.spacing(<span class="hljs-number">1</span>),
        <span class="hljs-attr">backgroundColor</span>: theme.palette.secondary.main
    },
    <span class="hljs-attr">form</span>: {
        <span class="hljs-attr">width</span>: <span class="hljs-string">'100%'</span>, <span class="hljs-comment">// Fix IE 11 issue.</span>
        <span class="hljs-attr">marginTop</span>: theme.spacing(<span class="hljs-number">3</span>)
    },
    <span class="hljs-attr">submit</span>: {
        <span class="hljs-attr">margin</span>: theme.spacing(<span class="hljs-number">3</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>)
    },
    <span class="hljs-attr">progess</span>: {
        <span class="hljs-attr">position</span>: <span class="hljs-string">'absolute'</span>
    }
});
</code></pre>
<p>We will create a class named signup which has a form and submit handler inside it.</p>
<pre><code class="lang-js"><span class="hljs-comment">// signup.js</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">signup</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span> </span>{
    <span class="hljs-keyword">constructor</span>(props) {
        <span class="hljs-built_in">super</span>(props);

        <span class="hljs-built_in">this</span>.state = {
            <span class="hljs-attr">firstName</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">lastName</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">country</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">username</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">email</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">password</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">confirmPassword</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">errors</span>: [],
            <span class="hljs-attr">loading</span>: <span class="hljs-literal">false</span>
        };
    }

    componentWillReceiveProps(nextProps) {
        <span class="hljs-keyword">if</span> (nextProps.UI.errors) {
            <span class="hljs-built_in">this</span>.setState({
                <span class="hljs-attr">errors</span>: nextProps.UI.errors
            });
        }
    }

    handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        <span class="hljs-built_in">this</span>.setState({
            [event.target.name]: event.target.value
        });
    };

    handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        event.preventDefault();
        <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">loading</span>: <span class="hljs-literal">true</span> });
        <span class="hljs-keyword">const</span> newUserData = {
            <span class="hljs-attr">firstName</span>: <span class="hljs-built_in">this</span>.state.firstName,
            <span class="hljs-attr">lastName</span>: <span class="hljs-built_in">this</span>.state.lastName,
            <span class="hljs-attr">phoneNumber</span>: <span class="hljs-built_in">this</span>.state.phoneNumber,
            <span class="hljs-attr">country</span>: <span class="hljs-built_in">this</span>.state.country,
            <span class="hljs-attr">username</span>: <span class="hljs-built_in">this</span>.state.username,
            <span class="hljs-attr">email</span>: <span class="hljs-built_in">this</span>.state.email,
            <span class="hljs-attr">password</span>: <span class="hljs-built_in">this</span>.state.password,
            <span class="hljs-attr">confirmPassword</span>: <span class="hljs-built_in">this</span>.state.confirmPassword
        };
        axios
            .post(<span class="hljs-string">'/signup'</span>, newUserData)
            .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
                <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'AuthToken'</span>, <span class="hljs-string">`<span class="hljs-subst">${response.data.token}</span>`</span>);
                <span class="hljs-built_in">this</span>.setState({ 
                    <span class="hljs-attr">loading</span>: <span class="hljs-literal">false</span>,
                });    
                <span class="hljs-built_in">this</span>.props.history.push(<span class="hljs-string">'/'</span>);
            })
            .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
                <span class="hljs-built_in">this</span>.setState({
                    <span class="hljs-attr">errors</span>: error.response.data,
                    <span class="hljs-attr">loading</span>: <span class="hljs-literal">false</span>
                });
            });
    };

    render() {
        <span class="hljs-keyword">const</span> { classes } = <span class="hljs-built_in">this</span>.props;
        <span class="hljs-keyword">const</span> { errors, loading } = <span class="hljs-built_in">this</span>.state;
        <span class="hljs-keyword">return</span> (
            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">component</span>=<span class="hljs-string">"main"</span> <span class="hljs-attr">maxWidth</span>=<span class="hljs-string">"xs"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">CssBaseline</span> /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.paper}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Avatar</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.avatar}</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">LockOutlinedIcon</span> /&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Avatar</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">component</span>=<span class="hljs-string">"h1"</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"h5"</span>&gt;</span>
                        Sign up
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.form}</span> <span class="hljs-attr">noValidate</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">container</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">{2}</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span> <span class="hljs-attr">sm</span>=<span class="hljs-string">{6}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                    <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                    <span class="hljs-attr">required</span>
                                    <span class="hljs-attr">fullWidth</span>
                                    <span class="hljs-attr">id</span>=<span class="hljs-string">"firstName"</span>
                                    <span class="hljs-attr">label</span>=<span class="hljs-string">"First Name"</span>
                                    <span class="hljs-attr">name</span>=<span class="hljs-string">"firstName"</span>
                                    <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"firstName"</span>
                                    <span class="hljs-attr">helperText</span>=<span class="hljs-string">{errors.firstName}</span>
                                    <span class="hljs-attr">error</span>=<span class="hljs-string">{errors.firstName</span> ? <span class="hljs-attr">true</span> <span class="hljs-attr">:</span> <span class="hljs-attr">false</span>}
                                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span> <span class="hljs-attr">sm</span>=<span class="hljs-string">{6}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                    <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                    <span class="hljs-attr">required</span>
                                    <span class="hljs-attr">fullWidth</span>
                                    <span class="hljs-attr">id</span>=<span class="hljs-string">"lastName"</span>
                                    <span class="hljs-attr">label</span>=<span class="hljs-string">"Last Name"</span>
                                    <span class="hljs-attr">name</span>=<span class="hljs-string">"lastName"</span>
                                    <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"lastName"</span>
                                    <span class="hljs-attr">helperText</span>=<span class="hljs-string">{errors.lastName}</span>
                                    <span class="hljs-attr">error</span>=<span class="hljs-string">{errors.lastName</span> ? <span class="hljs-attr">true</span> <span class="hljs-attr">:</span> <span class="hljs-attr">false</span>}
                                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>

                            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span> <span class="hljs-attr">sm</span>=<span class="hljs-string">{6}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                    <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                    <span class="hljs-attr">required</span>
                                    <span class="hljs-attr">fullWidth</span>
                                    <span class="hljs-attr">id</span>=<span class="hljs-string">"username"</span>
                                    <span class="hljs-attr">label</span>=<span class="hljs-string">"User Name"</span>
                                    <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span>
                                    <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"username"</span>
                                    <span class="hljs-attr">helperText</span>=<span class="hljs-string">{errors.username}</span>
                                    <span class="hljs-attr">error</span>=<span class="hljs-string">{errors.username</span> ? <span class="hljs-attr">true</span> <span class="hljs-attr">:</span> <span class="hljs-attr">false</span>}
                                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>

                            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span> <span class="hljs-attr">sm</span>=<span class="hljs-string">{6}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                    <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                    <span class="hljs-attr">required</span>
                                    <span class="hljs-attr">fullWidth</span>
                                    <span class="hljs-attr">id</span>=<span class="hljs-string">"phoneNumber"</span>
                                    <span class="hljs-attr">label</span>=<span class="hljs-string">"Phone Number"</span>
                                    <span class="hljs-attr">name</span>=<span class="hljs-string">"phoneNumber"</span>
                                    <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"phoneNumber"</span>
                                    <span class="hljs-attr">pattern</span>=<span class="hljs-string">"[7-9]{1}[0-9]{9}"</span>
                                    <span class="hljs-attr">helperText</span>=<span class="hljs-string">{errors.phoneNumber}</span>
                                    <span class="hljs-attr">error</span>=<span class="hljs-string">{errors.phoneNumber</span> ? <span class="hljs-attr">true</span> <span class="hljs-attr">:</span> <span class="hljs-attr">false</span>}
                                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>

                            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                    <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                    <span class="hljs-attr">required</span>
                                    <span class="hljs-attr">fullWidth</span>
                                    <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span>
                                    <span class="hljs-attr">label</span>=<span class="hljs-string">"Email Address"</span>
                                    <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span>
                                    <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"email"</span>
                                    <span class="hljs-attr">helperText</span>=<span class="hljs-string">{errors.email}</span>
                                    <span class="hljs-attr">error</span>=<span class="hljs-string">{errors.email</span> ? <span class="hljs-attr">true</span> <span class="hljs-attr">:</span> <span class="hljs-attr">false</span>}
                                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>

                            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                    <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                    <span class="hljs-attr">required</span>
                                    <span class="hljs-attr">fullWidth</span>
                                    <span class="hljs-attr">id</span>=<span class="hljs-string">"country"</span>
                                    <span class="hljs-attr">label</span>=<span class="hljs-string">"Country"</span>
                                    <span class="hljs-attr">name</span>=<span class="hljs-string">"country"</span>
                                    <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"country"</span>
                                    <span class="hljs-attr">helperText</span>=<span class="hljs-string">{errors.country}</span>
                                    <span class="hljs-attr">error</span>=<span class="hljs-string">{errors.country</span> ? <span class="hljs-attr">true</span> <span class="hljs-attr">:</span> <span class="hljs-attr">false</span>}
                                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>

                            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                    <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                    <span class="hljs-attr">required</span>
                                    <span class="hljs-attr">fullWidth</span>
                                    <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span>
                                    <span class="hljs-attr">label</span>=<span class="hljs-string">"Password"</span>
                                    <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
                                    <span class="hljs-attr">id</span>=<span class="hljs-string">"password"</span>
                                    <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"current-password"</span>
                                    <span class="hljs-attr">helperText</span>=<span class="hljs-string">{errors.password}</span>
                                    <span class="hljs-attr">error</span>=<span class="hljs-string">{errors.password</span> ? <span class="hljs-attr">true</span> <span class="hljs-attr">:</span> <span class="hljs-attr">false</span>}
                                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                    <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                    <span class="hljs-attr">required</span>
                                    <span class="hljs-attr">fullWidth</span>
                                    <span class="hljs-attr">name</span>=<span class="hljs-string">"confirmPassword"</span>
                                    <span class="hljs-attr">label</span>=<span class="hljs-string">"Confirm Password"</span>
                                    <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
                                    <span class="hljs-attr">id</span>=<span class="hljs-string">"confirmPassword"</span>
                                    <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"current-password"</span>
                                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
                            <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
                            <span class="hljs-attr">fullWidth</span>
                            <span class="hljs-attr">variant</span>=<span class="hljs-string">"contained"</span>
                            <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span>
                            <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.submit}</span>
                            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{this.handleSubmit}</span>
                            <span class="hljs-attr">disabled</span>=<span class="hljs-string">{loading</span> || 
                                !<span class="hljs-attr">this.state.email</span> || 
                                !<span class="hljs-attr">this.state.password</span> ||
                                !<span class="hljs-attr">this.state.firstName</span> || 
                                !<span class="hljs-attr">this.state.lastName</span> ||
                                !<span class="hljs-attr">this.state.country</span> || 
                                !<span class="hljs-attr">this.state.username</span> || 
                                !<span class="hljs-attr">this.state.phoneNumber</span>}
                        &gt;</span>
                            Sign Up
                            {loading &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">CircularProgress</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{30}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.progess}</span> /&gt;</span>}
                        <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">container</span> <span class="hljs-attr">justify</span>=<span class="hljs-string">"flex-end"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"login"</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"body2"</span>&gt;</span>
                                    Already have an account? Sign in
                                <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span></span>
        );
    }
}
</code></pre>
<p>At the end of this file add the following export:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> withStyles(styles)(signup);
</code></pre>
<p>The logic for the Signup component is the same as the login component. Go to the browser at <code>[http://localhost:3000/signup](http://localhost:3000/signup)</code> and you’ll see the following Signup UI. Once the Signup is successful we will be routed back to the Home page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/SignupPage.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Sign up Form</em></p>
<p>Try filling wrong credentials or sending an empty request and you will get the errors. Send a valid request. Go to the <strong>Developer console &gt; Application</strong>. You will see that users token is store in the Local storage.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/DevConsoleSignup.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Chrome Developer Console</em></p>
<h3 id="heading-4-account-section">4. Account Section:</h3>
<p>To build the account page we will need to first create our <strong>Home page</strong> from where we will load the <strong>account section</strong>. Go to the <code>App.js</code> and update the following route:</p>
<pre><code class="lang-js"><span class="hljs-comment">// App.js</span>

&lt;Route exact path=<span class="hljs-string">"/"</span> component={home}/&gt;
</code></pre>
<p>Don't forget the import:</p>
<pre><code class="lang-js"><span class="hljs-comment">// App.js</span>

<span class="hljs-keyword">import</span> home <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/home'</span>;
</code></pre>
<p>Create a new file named <code>home.js</code> . This file will be the index of our application. The Account and Todo sections both load on this page based on the button click.</p>
<p>Import the Material UI packages, Axios package, our custom Account, todo components, and auth middleware.</p>
<pre><code class="lang-js"><span class="hljs-comment">// home.js</span>

<span class="hljs-keyword">import</span> React, { Component } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;

<span class="hljs-keyword">import</span> Account <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/account'</span>;
<span class="hljs-keyword">import</span> Todo <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/todo'</span>;

<span class="hljs-keyword">import</span> Drawer <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Drawer'</span>;
<span class="hljs-keyword">import</span> AppBar <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/AppBar'</span>;
<span class="hljs-keyword">import</span> CssBaseline <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/CssBaseline'</span>;
<span class="hljs-keyword">import</span> Toolbar <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Toolbar'</span>;
<span class="hljs-keyword">import</span> List <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/List'</span>;
<span class="hljs-keyword">import</span> Typography <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Typography'</span>;
<span class="hljs-keyword">import</span> Divider <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Divider'</span>;
<span class="hljs-keyword">import</span> ListItem <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/ListItem'</span>;
<span class="hljs-keyword">import</span> ListItemIcon <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/ListItemIcon'</span>;
<span class="hljs-keyword">import</span> ListItemText <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/ListItemText'</span>;
<span class="hljs-keyword">import</span> withStyles <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/styles/withStyles'</span>;
<span class="hljs-keyword">import</span> AccountBoxIcon <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/icons/AccountBox'</span>;
<span class="hljs-keyword">import</span> NotesIcon <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/icons/Notes'</span>;
<span class="hljs-keyword">import</span> Avatar <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/avatar'</span>;
<span class="hljs-keyword">import</span> ExitToAppIcon <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/icons/ExitToApp'</span>;
<span class="hljs-keyword">import</span> CircularProgress <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/CircularProgress'</span>;

<span class="hljs-keyword">import</span> { authMiddleWare } <span class="hljs-keyword">from</span> <span class="hljs-string">'../util/auth'</span>
</code></pre>
<p>We will set our drawerWidth as follows:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> drawerWidth = <span class="hljs-number">240</span>;
</code></pre>
<p>We will add the following style to our Home page:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> styles = <span class="hljs-function">(<span class="hljs-params">theme</span>) =&gt;</span> ({
    <span class="hljs-attr">root</span>: {
        <span class="hljs-attr">display</span>: <span class="hljs-string">'flex'</span>
    },
    <span class="hljs-attr">appBar</span>: {
        <span class="hljs-attr">zIndex</span>: theme.zIndex.drawer + <span class="hljs-number">1</span>
    },
    <span class="hljs-attr">drawer</span>: {
        <span class="hljs-attr">width</span>: drawerWidth,
        <span class="hljs-attr">flexShrink</span>: <span class="hljs-number">0</span>
    },
    <span class="hljs-attr">drawerPaper</span>: {
        <span class="hljs-attr">width</span>: drawerWidth
    },
    <span class="hljs-attr">content</span>: {
        <span class="hljs-attr">flexGrow</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">padding</span>: theme.spacing(<span class="hljs-number">3</span>)
    },
    <span class="hljs-attr">avatar</span>: {
        <span class="hljs-attr">height</span>: <span class="hljs-number">110</span>,
        <span class="hljs-attr">width</span>: <span class="hljs-number">100</span>,
        <span class="hljs-attr">flexShrink</span>: <span class="hljs-number">0</span>,
        <span class="hljs-attr">flexGrow</span>: <span class="hljs-number">0</span>,
        <span class="hljs-attr">marginTop</span>: <span class="hljs-number">20</span>
    },
    <span class="hljs-attr">uiProgess</span>: {
        <span class="hljs-attr">position</span>: <span class="hljs-string">'fixed'</span>,
        <span class="hljs-attr">zIndex</span>: <span class="hljs-string">'1000'</span>,
        <span class="hljs-attr">height</span>: <span class="hljs-string">'31px'</span>,
        <span class="hljs-attr">width</span>: <span class="hljs-string">'31px'</span>,
        <span class="hljs-attr">left</span>: <span class="hljs-string">'50%'</span>,
        <span class="hljs-attr">top</span>: <span class="hljs-string">'35%'</span>
    },
    <span class="hljs-attr">toolbar</span>: theme.mixins.toolbar
});
</code></pre>
<p>We will create a class named home. This class will have an API call to get the User's profile picture, First name and Last name. Also it will have logic to choose which component to display, either Todo or Account:</p>
<pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">home</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span> </span>{
    state = {
        <span class="hljs-attr">render</span>: <span class="hljs-literal">false</span>
    };

    loadAccountPage = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">render</span>: <span class="hljs-literal">true</span> });
    };

    loadTodoPage = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">render</span>: <span class="hljs-literal">false</span> });
    };

    logoutHandler = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        <span class="hljs-built_in">localStorage</span>.removeItem(<span class="hljs-string">'AuthToken'</span>);
        <span class="hljs-built_in">this</span>.props.history.push(<span class="hljs-string">'/login'</span>);
    };

    <span class="hljs-keyword">constructor</span>(props) {
        <span class="hljs-built_in">super</span>(props);

        <span class="hljs-built_in">this</span>.state = {
            <span class="hljs-attr">firstName</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">lastName</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">profilePicture</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">uiLoading</span>: <span class="hljs-literal">true</span>,
            <span class="hljs-attr">imageLoading</span>: <span class="hljs-literal">false</span>
        };
    }

    componentWillMount = <span class="hljs-function">() =&gt;</span> {
        authMiddleWare(<span class="hljs-built_in">this</span>.props.history);
        <span class="hljs-keyword">const</span> authToken = <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'AuthToken'</span>);
        axios.defaults.headers.common = { <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`<span class="hljs-subst">${authToken}</span>`</span> };
        axios
            .get(<span class="hljs-string">'/user'</span>)
            .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
                <span class="hljs-built_in">console</span>.log(response.data);
                <span class="hljs-built_in">this</span>.setState({
                    <span class="hljs-attr">firstName</span>: response.data.userCredentials.firstName,
                    <span class="hljs-attr">lastName</span>: response.data.userCredentials.lastName,
                    <span class="hljs-attr">email</span>: response.data.userCredentials.email,
                    <span class="hljs-attr">phoneNumber</span>: response.data.userCredentials.phoneNumber,
                    <span class="hljs-attr">country</span>: response.data.userCredentials.country,
                    <span class="hljs-attr">username</span>: response.data.userCredentials.username,
                    <span class="hljs-attr">uiLoading</span>: <span class="hljs-literal">false</span>,
                    <span class="hljs-attr">profilePicture</span>: response.data.userCredentials.imageUrl
                });
            })
            .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
                <span class="hljs-keyword">if</span>(error.response.status === <span class="hljs-number">403</span>) {
                    <span class="hljs-built_in">this</span>.props.history.push(<span class="hljs-string">'/login'</span>)
                }
                <span class="hljs-built_in">console</span>.log(error);
                <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">errorMsg</span>: <span class="hljs-string">'Error in retrieving the data'</span> });
            });
    };

    render() {
        <span class="hljs-keyword">const</span> { classes } = <span class="hljs-built_in">this</span>.props;        
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.state.uiLoading === <span class="hljs-literal">true</span>) {
            <span class="hljs-keyword">return</span> (
                <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.root}</span>&gt;</span>
                    {this.state.uiLoading &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">CircularProgress</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{150}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.uiProgess}</span> /&gt;</span>}
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
            );
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> (
                <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.root}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">CssBaseline</span> /&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">AppBar</span> <span class="hljs-attr">position</span>=<span class="hljs-string">"fixed"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.appBar}</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Toolbar</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"h6"</span> <span class="hljs-attr">noWrap</span>&gt;</span>
                                TodoApp
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">Toolbar</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">AppBar</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Drawer</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.drawer}</span>
                        <span class="hljs-attr">variant</span>=<span class="hljs-string">"permanent"</span>
                        <span class="hljs-attr">classes</span>=<span class="hljs-string">{{</span>
                            <span class="hljs-attr">paper:</span> <span class="hljs-attr">classes.drawerPaper</span>
                        }}
                    &gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.toolbar}</span> /&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Divider</span> /&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">center</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Avatar</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{this.state.profilePicture}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.avatar}</span> /&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
                                {' '}
                                {this.state.firstName} {this.state.lastName}
                            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">center</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Divider</span> /&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">List</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">ListItem</span> <span class="hljs-attr">button</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"Todo"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{this.loadTodoPage}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">ListItemIcon</span>&gt;</span>
                                    {' '}
                                    <span class="hljs-tag">&lt;<span class="hljs-name">NotesIcon</span> /&gt;</span>{' '}
                                <span class="hljs-tag">&lt;/<span class="hljs-name">ListItemIcon</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">ListItemText</span> <span class="hljs-attr">primary</span>=<span class="hljs-string">"Todo"</span> /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">ListItem</span>&gt;</span>

                            <span class="hljs-tag">&lt;<span class="hljs-name">ListItem</span> <span class="hljs-attr">button</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"Account"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{this.loadAccountPage}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">ListItemIcon</span>&gt;</span>
                                    {' '}
                                    <span class="hljs-tag">&lt;<span class="hljs-name">AccountBoxIcon</span> /&gt;</span>{' '}
                                <span class="hljs-tag">&lt;/<span class="hljs-name">ListItemIcon</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">ListItemText</span> <span class="hljs-attr">primary</span>=<span class="hljs-string">"Account"</span> /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">ListItem</span>&gt;</span>

                            <span class="hljs-tag">&lt;<span class="hljs-name">ListItem</span> <span class="hljs-attr">button</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"Logout"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{this.logoutHandler}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">ListItemIcon</span>&gt;</span>
                                    {' '}
                                    <span class="hljs-tag">&lt;<span class="hljs-name">ExitToAppIcon</span> /&gt;</span>{' '}
                                <span class="hljs-tag">&lt;/<span class="hljs-name">ListItemIcon</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">ListItemText</span> <span class="hljs-attr">primary</span>=<span class="hljs-string">"Logout"</span> /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">ListItem</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">List</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Drawer</span>&gt;</span>

                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{this.state.render ? <span class="hljs-tag">&lt;<span class="hljs-name">Account</span> /&gt;</span> : <span class="hljs-tag">&lt;<span class="hljs-name">Todo</span> /&gt;</span>}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
            );
        }
    }
}
</code></pre>
<p>Here in the code, you will see that <code>authMiddleWare(this.props.history);</code> is used. This middleware checks if the authToken is null. If yes then it will push the user back to the <code>login.js</code>. This is added so that our user cannot access the <code>/</code> route without Signup or log in. At the end of this file add the following export:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> withStyles(styles)(home);
</code></pre>
<p>Now are you wondering what this code from <code>home.js</code> does?</p>
<pre><code class="lang-python">&lt;div&gt;{this.state.render ? &lt;Account /&gt; : &lt;Todo /&gt;}&lt;/div&gt;
</code></pre>
<p>It is checking the render state which we are setting on the button click. Let's create the component directory, and under that directory create two files: <code>account.js</code> and <code>todo.js</code>.</p>
<p>Let’s create a directory named <strong>util</strong> and file named <code>auth.js</code> under that directory. Copy-paste the following code under <code>auth.js</code> :</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> authMiddleWare = <span class="hljs-function">(<span class="hljs-params">history</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> authToken = <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'AuthToken'</span>);
    <span class="hljs-keyword">if</span>(authToken === <span class="hljs-literal">null</span>){
        history.push(<span class="hljs-string">'/login'</span>)
    }
}
</code></pre>
<p>For time being inside the <code>todo.js</code> file we will just write a class which renders the text <strong>Hello I am todo</strong>. We will be working on our todos in the next section:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { Component } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">import</span> withStyles <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/styles/withStyles'</span>;
<span class="hljs-keyword">import</span> Typography <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Typography'</span>;

<span class="hljs-keyword">const</span> styles = (<span class="hljs-function">(<span class="hljs-params">theme</span>) =&gt;</span> ({
    <span class="hljs-attr">content</span>: {
        <span class="hljs-attr">flexGrow</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">padding</span>: theme.spacing(<span class="hljs-number">3</span>),
    },
    <span class="hljs-attr">toolbar</span>: theme.mixins.toolbar,
    })
);

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">todo</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span> </span>{
    render() {
        <span class="hljs-keyword">const</span> { classes } = <span class="hljs-built_in">this</span>.props;
        <span class="hljs-keyword">return</span> (
            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.content}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.toolbar}</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">paragraph</span>&gt;</span>
                Hello I am todo
            <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
        )
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> (withStyles(styles)(todo));
</code></pre>
<p>Now it's time for the account section. Import the Material UI, clsx, axios and authmiddleWare utility in our <code>account.js</code>.</p>
<pre><code class="lang-js"><span class="hljs-comment">// account.js</span>

<span class="hljs-keyword">import</span> React, { Component } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> withStyles <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/styles/withStyles'</span>;
<span class="hljs-keyword">import</span> Typography <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Typography'</span>;
<span class="hljs-keyword">import</span> CircularProgress <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/CircularProgress'</span>;
<span class="hljs-keyword">import</span> CloudUploadIcon <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/icons/CloudUpload'</span>;
<span class="hljs-keyword">import</span> { Card, CardActions, CardContent, Divider, Button, Grid, TextField } <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core'</span>;

<span class="hljs-keyword">import</span> clsx <span class="hljs-keyword">from</span> <span class="hljs-string">'clsx'</span>;

<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
<span class="hljs-keyword">import</span> { authMiddleWare } <span class="hljs-keyword">from</span> <span class="hljs-string">'../util/auth'</span>;
</code></pre>
<p>We will add the following styling to our Account page:</p>
<pre><code class="lang-js"><span class="hljs-comment">// account.js</span>

<span class="hljs-keyword">const</span> styles = <span class="hljs-function">(<span class="hljs-params">theme</span>) =&gt;</span> ({
    <span class="hljs-attr">content</span>: {
        <span class="hljs-attr">flexGrow</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">padding</span>: theme.spacing(<span class="hljs-number">3</span>)
    },
    <span class="hljs-attr">toolbar</span>: theme.mixins.toolbar,
    <span class="hljs-attr">root</span>: {},
    <span class="hljs-attr">details</span>: {
        <span class="hljs-attr">display</span>: <span class="hljs-string">'flex'</span>
    },
    <span class="hljs-attr">avatar</span>: {
        <span class="hljs-attr">height</span>: <span class="hljs-number">110</span>,
        <span class="hljs-attr">width</span>: <span class="hljs-number">100</span>,
        <span class="hljs-attr">flexShrink</span>: <span class="hljs-number">0</span>,
        <span class="hljs-attr">flexGrow</span>: <span class="hljs-number">0</span>
    },
    <span class="hljs-attr">locationText</span>: {
        <span class="hljs-attr">paddingLeft</span>: <span class="hljs-string">'15px'</span>
    },
    <span class="hljs-attr">buttonProperty</span>: {
        <span class="hljs-attr">position</span>: <span class="hljs-string">'absolute'</span>,
        <span class="hljs-attr">top</span>: <span class="hljs-string">'50%'</span>
    },
    <span class="hljs-attr">uiProgess</span>: {
        <span class="hljs-attr">position</span>: <span class="hljs-string">'fixed'</span>,
        <span class="hljs-attr">zIndex</span>: <span class="hljs-string">'1000'</span>,
        <span class="hljs-attr">height</span>: <span class="hljs-string">'31px'</span>,
        <span class="hljs-attr">width</span>: <span class="hljs-string">'31px'</span>,
        <span class="hljs-attr">left</span>: <span class="hljs-string">'50%'</span>,
        <span class="hljs-attr">top</span>: <span class="hljs-string">'35%'</span>
    },
    <span class="hljs-attr">progess</span>: {
        <span class="hljs-attr">position</span>: <span class="hljs-string">'absolute'</span>
    },
    <span class="hljs-attr">uploadButton</span>: {
        <span class="hljs-attr">marginLeft</span>: <span class="hljs-string">'8px'</span>,
        <span class="hljs-attr">margin</span>: theme.spacing(<span class="hljs-number">1</span>)
    },
    <span class="hljs-attr">customError</span>: {
        <span class="hljs-attr">color</span>: <span class="hljs-string">'red'</span>,
        <span class="hljs-attr">fontSize</span>: <span class="hljs-string">'0.8rem'</span>,
        <span class="hljs-attr">marginTop</span>: <span class="hljs-number">10</span>
    },
    <span class="hljs-attr">submitButton</span>: {
        <span class="hljs-attr">marginTop</span>: <span class="hljs-string">'10px'</span>
    }
});
</code></pre>
<p>We will create a class component named account. For the time being just copy-paste the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">// account.js</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">account</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span> </span>{
    <span class="hljs-keyword">constructor</span>(props) {
        <span class="hljs-built_in">super</span>(props);

        <span class="hljs-built_in">this</span>.state = {
            <span class="hljs-attr">firstName</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">lastName</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">email</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">username</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">country</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">profilePicture</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">uiLoading</span>: <span class="hljs-literal">true</span>,
            <span class="hljs-attr">buttonLoading</span>: <span class="hljs-literal">false</span>,
            <span class="hljs-attr">imageError</span>: <span class="hljs-string">''</span>
        };
    }

    componentWillMount = <span class="hljs-function">() =&gt;</span> {
        authMiddleWare(<span class="hljs-built_in">this</span>.props.history);
        <span class="hljs-keyword">const</span> authToken = <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'AuthToken'</span>);
        axios.defaults.headers.common = { <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`<span class="hljs-subst">${authToken}</span>`</span> };
        axios
            .get(<span class="hljs-string">'/user'</span>)
            .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
                <span class="hljs-built_in">console</span>.log(response.data);
                <span class="hljs-built_in">this</span>.setState({
                    <span class="hljs-attr">firstName</span>: response.data.userCredentials.firstName,
                    <span class="hljs-attr">lastName</span>: response.data.userCredentials.lastName,
                    <span class="hljs-attr">email</span>: response.data.userCredentials.email,
                    <span class="hljs-attr">phoneNumber</span>: response.data.userCredentials.phoneNumber,
                    <span class="hljs-attr">country</span>: response.data.userCredentials.country,
                    <span class="hljs-attr">username</span>: response.data.userCredentials.username,
                    <span class="hljs-attr">uiLoading</span>: <span class="hljs-literal">false</span>
                });
            })
            .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
                <span class="hljs-keyword">if</span> (error.response.status === <span class="hljs-number">403</span>) {
                    <span class="hljs-built_in">this</span>.props.history.push(<span class="hljs-string">'/login'</span>);
                }
                <span class="hljs-built_in">console</span>.log(error);
                <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">errorMsg</span>: <span class="hljs-string">'Error in retrieving the data'</span> });
            });
    };

    handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        <span class="hljs-built_in">this</span>.setState({
            [event.target.name]: event.target.value
        });
    };

    handleImageChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        <span class="hljs-built_in">this</span>.setState({
            <span class="hljs-attr">image</span>: event.target.files[<span class="hljs-number">0</span>]
        });
    };

    profilePictureHandler = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        event.preventDefault();
        <span class="hljs-built_in">this</span>.setState({
            <span class="hljs-attr">uiLoading</span>: <span class="hljs-literal">true</span>
        });
        authMiddleWare(<span class="hljs-built_in">this</span>.props.history);
        <span class="hljs-keyword">const</span> authToken = <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'AuthToken'</span>);
        <span class="hljs-keyword">let</span> form_data = <span class="hljs-keyword">new</span> FormData();
        form_data.append(<span class="hljs-string">'image'</span>, <span class="hljs-built_in">this</span>.state.image);
        form_data.append(<span class="hljs-string">'content'</span>, <span class="hljs-built_in">this</span>.state.content);
        axios.defaults.headers.common = { <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`<span class="hljs-subst">${authToken}</span>`</span> };
        axios
            .post(<span class="hljs-string">'/user/image'</span>, form_data, {
                <span class="hljs-attr">headers</span>: {
                    <span class="hljs-string">'content-type'</span>: <span class="hljs-string">'multipart/form-data'</span>
                }
            })
            .then(<span class="hljs-function">() =&gt;</span> {
                <span class="hljs-built_in">window</span>.location.reload();
            })
            .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
                <span class="hljs-keyword">if</span> (error.response.status === <span class="hljs-number">403</span>) {
                    <span class="hljs-built_in">this</span>.props.history.push(<span class="hljs-string">'/login'</span>);
                }
                <span class="hljs-built_in">console</span>.log(error);
                <span class="hljs-built_in">this</span>.setState({
                    <span class="hljs-attr">uiLoading</span>: <span class="hljs-literal">false</span>,
                    <span class="hljs-attr">imageError</span>: <span class="hljs-string">'Error in posting the data'</span>
                });
            });
    };

    updateFormValues = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        event.preventDefault();
        <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">buttonLoading</span>: <span class="hljs-literal">true</span> });
        authMiddleWare(<span class="hljs-built_in">this</span>.props.history);
        <span class="hljs-keyword">const</span> authToken = <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'AuthToken'</span>);
        axios.defaults.headers.common = { <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`<span class="hljs-subst">${authToken}</span>`</span> };
        <span class="hljs-keyword">const</span> formRequest = {
            <span class="hljs-attr">firstName</span>: <span class="hljs-built_in">this</span>.state.firstName,
            <span class="hljs-attr">lastName</span>: <span class="hljs-built_in">this</span>.state.lastName,
            <span class="hljs-attr">country</span>: <span class="hljs-built_in">this</span>.state.country
        };
        axios
            .post(<span class="hljs-string">'/user'</span>, formRequest)
            .then(<span class="hljs-function">() =&gt;</span> {
                <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">buttonLoading</span>: <span class="hljs-literal">false</span> });
            })
            .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
                <span class="hljs-keyword">if</span> (error.response.status === <span class="hljs-number">403</span>) {
                    <span class="hljs-built_in">this</span>.props.history.push(<span class="hljs-string">'/login'</span>);
                }
                <span class="hljs-built_in">console</span>.log(error);
                <span class="hljs-built_in">this</span>.setState({
                    <span class="hljs-attr">buttonLoading</span>: <span class="hljs-literal">false</span>
                });
            });
    };

    render() {
        <span class="hljs-keyword">const</span> { classes, ...rest } = <span class="hljs-built_in">this</span>.props;
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.state.uiLoading === <span class="hljs-literal">true</span>) {
            <span class="hljs-keyword">return</span> (
                <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.content}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.toolbar}</span> /&gt;</span>
                    {this.state.uiLoading &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">CircularProgress</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{150}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.uiProgess}</span> /&gt;</span>}
                <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
            );
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> (
                <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.content}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.toolbar}</span> /&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Card</span> {<span class="hljs-attr">...rest</span>} <span class="hljs-attr">className</span>=<span class="hljs-string">{clsx(classes.root,</span> <span class="hljs-attr">classes</span>)}&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">CardContent</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.details}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.locationText}</span> <span class="hljs-attr">gutterBottom</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"h4"</span>&gt;</span>
                                        {this.state.firstName} {this.state.lastName}
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
                                        <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                        <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span>
                                        <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
                                        <span class="hljs-attr">size</span>=<span class="hljs-string">"small"</span>
                                        <span class="hljs-attr">startIcon</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">CloudUploadIcon</span> /&gt;</span>}
                                        className={classes.uploadButton}
                                        onClick={this.profilePictureHandler}
                                    &gt;
                                        Upload Photo
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"file"</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleImageChange}</span> /&gt;</span>

                                    {this.state.imageError ? (
                                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.customError}</span>&gt;</span>
                                            {' '}
                                            Wrong Image Format || Supported Format are PNG and JPG
                                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                                    ) : (
                                        false
                                    )}
                                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.progress}</span> /&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">CardContent</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Divider</span> /&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Card</span>&gt;</span>

                    <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Card</span> {<span class="hljs-attr">...rest</span>} <span class="hljs-attr">className</span>=<span class="hljs-string">{clsx(classes.root,</span> <span class="hljs-attr">classes</span>)}&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"off"</span> <span class="hljs-attr">noValidate</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Divider</span> /&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">CardContent</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">container</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">{3}</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">md</span>=<span class="hljs-string">{6}</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                            <span class="hljs-attr">fullWidth</span>
                                            <span class="hljs-attr">label</span>=<span class="hljs-string">"First name"</span>
                                            <span class="hljs-attr">margin</span>=<span class="hljs-string">"dense"</span>
                                            <span class="hljs-attr">name</span>=<span class="hljs-string">"firstName"</span>
                                            <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                            <span class="hljs-attr">value</span>=<span class="hljs-string">{this.state.firstName}</span>
                                            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                        /&gt;</span>
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">md</span>=<span class="hljs-string">{6}</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                            <span class="hljs-attr">fullWidth</span>
                                            <span class="hljs-attr">label</span>=<span class="hljs-string">"Last name"</span>
                                            <span class="hljs-attr">margin</span>=<span class="hljs-string">"dense"</span>
                                            <span class="hljs-attr">name</span>=<span class="hljs-string">"lastName"</span>
                                            <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                            <span class="hljs-attr">value</span>=<span class="hljs-string">{this.state.lastName}</span>
                                            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                        /&gt;</span>
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">md</span>=<span class="hljs-string">{6}</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                            <span class="hljs-attr">fullWidth</span>
                                            <span class="hljs-attr">label</span>=<span class="hljs-string">"Email"</span>
                                            <span class="hljs-attr">margin</span>=<span class="hljs-string">"dense"</span>
                                            <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span>
                                            <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                            <span class="hljs-attr">disabled</span>=<span class="hljs-string">{true}</span>
                                            <span class="hljs-attr">value</span>=<span class="hljs-string">{this.state.email}</span>
                                            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                        /&gt;</span>
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">md</span>=<span class="hljs-string">{6}</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                            <span class="hljs-attr">fullWidth</span>
                                            <span class="hljs-attr">label</span>=<span class="hljs-string">"Phone Number"</span>
                                            <span class="hljs-attr">margin</span>=<span class="hljs-string">"dense"</span>
                                            <span class="hljs-attr">name</span>=<span class="hljs-string">"phone"</span>
                                            <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span>
                                            <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                            <span class="hljs-attr">disabled</span>=<span class="hljs-string">{true}</span>
                                            <span class="hljs-attr">value</span>=<span class="hljs-string">{this.state.phoneNumber}</span>
                                            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                        /&gt;</span>
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">md</span>=<span class="hljs-string">{6}</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                            <span class="hljs-attr">fullWidth</span>
                                            <span class="hljs-attr">label</span>=<span class="hljs-string">"User Name"</span>
                                            <span class="hljs-attr">margin</span>=<span class="hljs-string">"dense"</span>
                                            <span class="hljs-attr">name</span>=<span class="hljs-string">"userHandle"</span>
                                            <span class="hljs-attr">disabled</span>=<span class="hljs-string">{true}</span>
                                            <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                            <span class="hljs-attr">value</span>=<span class="hljs-string">{this.state.username}</span>
                                            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                        /&gt;</span>
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">md</span>=<span class="hljs-string">{6}</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                            <span class="hljs-attr">fullWidth</span>
                                            <span class="hljs-attr">label</span>=<span class="hljs-string">"Country"</span>
                                            <span class="hljs-attr">margin</span>=<span class="hljs-string">"dense"</span>
                                            <span class="hljs-attr">name</span>=<span class="hljs-string">"country"</span>
                                            <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                            <span class="hljs-attr">value</span>=<span class="hljs-string">{this.state.country}</span>
                                            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                        /&gt;</span>
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                                <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">CardContent</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Divider</span> /&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">CardActions</span> /&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Card</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
                        <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span>
                        <span class="hljs-attr">variant</span>=<span class="hljs-string">"contained"</span>
                        <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.submitButton}</span>
                        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{this.updateFormValues}</span>
                        <span class="hljs-attr">disabled</span>=<span class="hljs-string">{</span>
                            <span class="hljs-attr">this.state.buttonLoading</span> ||
                            !<span class="hljs-attr">this.state.firstName</span> ||
                            !<span class="hljs-attr">this.state.lastName</span> ||
                            !<span class="hljs-attr">this.state.country</span>
                        }
                    &gt;</span>
                        Save details
                        {this.state.buttonLoading &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">CircularProgress</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{30}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.progess}</span> /&gt;</span>}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
            );
        }
    }
}
</code></pre>
<p>At the end of this file add the following export:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> withStyles(styles)(account);
</code></pre>
<p>In <code>account.js</code> there are lot of components used. First let's see how our application looks. After that I'll explain all the components that are used and why they are used.</p>
<p>Go to the browser, and if your token is expired it will redirect you to the <code>login</code> page. Add your details and log in again. Once you've done that, go to the Account tab and you will find the following UI:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/image-88.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Account Section</em></p>
<p>There are 3 handlers in the Account Section:</p>
<ol>
<li><p><strong>componentWillMount</strong>: This is React's inbuilt lifecycle method. We are using it to load the data before the render lifecycle and update our state values.</p>
</li>
<li><p><strong>ProfilePictureUpdate:</strong> This is our custom handler that we are using so that when our user clicks on the Upload Photo button then it will send the data to a server and reload the page to show the user's new Profile Picture.</p>
</li>
<li><p><strong>updateFormValues:</strong> This is also our custom handler to update the User's details. Here, the user can update their first name, last name, and country. We are not allowing email and username updates because our backend logic depends on those keys.</p>
</li>
</ol>
<p>Other than these 3 handlers it is a form page with styling on top of it. Here is the directory structure up to this point inside the view folder:</p>
<pre><code class="lang-shell">+-- public 
+-- src
|   +-- components
|   +-- +-- todo.js
|   +-- +-- account.js
|   +-- pages
|   +-- +-- home.js
|   +-- +-- login.js
|   +-- +-- signup.js
|   +-- util
|   +-- +-- auth.js 
|   +-- README.md
|   +-- package-lock.json
|   +-- package.json
|   +-- .gitignore
</code></pre>
<p>With this we have completed our Account Dashboard. Now go have a coffee, take a break and in the next section, we will build the Todo Dashboard.</p>
<h2 id="heading-section-4-todo-dashboard">Section 4: Todo Dashboard</h2>
<p>In this section**,** we are going to develop the UI for these features of the Todos Dashboard:</p>
<ol>
<li><p><strong>Add a Todo:</strong></p>
</li>
<li><p><strong>Get all todos:</strong></p>
</li>
<li><p><strong>Delete a todo</strong></p>
</li>
<li><p><strong>Edit a todo</strong></p>
</li>
<li><p><strong>Get a todo</strong></p>
</li>
<li><p><strong>Applying Theme</strong></p>
</li>
</ol>
<p>The Todo Dashboard code implemented in this section can be found at this <a target="_blank" href="https://github.com/Sharvin26/TodoApp/tree/3799980aa13eeb8d313e17d83aa3032748aedb00/view">commit</a>.</p>
<p>Go to <code>todos.js</code> under the <strong>components</strong> directory. Add the following imports to the existing imports:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Button'</span>;
<span class="hljs-keyword">import</span> Dialog <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Dialog'</span>;
<span class="hljs-keyword">import</span> AddCircleIcon <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/icons/AddCircle'</span>;
<span class="hljs-keyword">import</span> AppBar <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/AppBar'</span>;
<span class="hljs-keyword">import</span> Toolbar <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Toolbar'</span>;
<span class="hljs-keyword">import</span> IconButton <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/IconButton'</span>;
<span class="hljs-keyword">import</span> CloseIcon <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/icons/Close'</span>;
<span class="hljs-keyword">import</span> Slide <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Slide'</span>;
<span class="hljs-keyword">import</span> TextField <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/TextField'</span>;
<span class="hljs-keyword">import</span> Grid <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Grid'</span>;
<span class="hljs-keyword">import</span> Card <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Card'</span>;
<span class="hljs-keyword">import</span> CardActions <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/CardActions'</span>;
<span class="hljs-keyword">import</span> CircularProgress <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/CircularProgress'</span>;
<span class="hljs-keyword">import</span> CardContent <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/CardContent'</span>;
<span class="hljs-keyword">import</span> MuiDialogTitle <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/DialogTitle'</span>;
<span class="hljs-keyword">import</span> MuiDialogContent <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/DialogContent'</span>;

<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
<span class="hljs-keyword">import</span> dayjs <span class="hljs-keyword">from</span> <span class="hljs-string">'dayjs'</span>;
<span class="hljs-keyword">import</span> relativeTime <span class="hljs-keyword">from</span> <span class="hljs-string">'dayjs/plugin/relativeTime'</span>;
<span class="hljs-keyword">import</span> { authMiddleWare } <span class="hljs-keyword">from</span> <span class="hljs-string">'../util/auth'</span>;
</code></pre>
<p>We also need to add the following CSS elements in the existing style components:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> styles = <span class="hljs-function">(<span class="hljs-params">theme</span>) =&gt;</span> ({
    .., <span class="hljs-comment">// Existing CSS elements</span>
    <span class="hljs-attr">title</span>: {
        <span class="hljs-attr">marginLeft</span>: theme.spacing(<span class="hljs-number">2</span>),
        <span class="hljs-attr">flex</span>: <span class="hljs-number">1</span>
    },
    <span class="hljs-attr">submitButton</span>: {
        <span class="hljs-attr">display</span>: <span class="hljs-string">'block'</span>,
        <span class="hljs-attr">color</span>: <span class="hljs-string">'white'</span>,
        <span class="hljs-attr">textAlign</span>: <span class="hljs-string">'center'</span>,
        <span class="hljs-attr">position</span>: <span class="hljs-string">'absolute'</span>,
        <span class="hljs-attr">top</span>: <span class="hljs-number">14</span>,
        <span class="hljs-attr">right</span>: <span class="hljs-number">10</span>
    },
    <span class="hljs-attr">floatingButton</span>: {
        <span class="hljs-attr">position</span>: <span class="hljs-string">'fixed'</span>,
        <span class="hljs-attr">bottom</span>: <span class="hljs-number">0</span>,
        <span class="hljs-attr">right</span>: <span class="hljs-number">0</span>
    },
    <span class="hljs-attr">form</span>: {
        <span class="hljs-attr">width</span>: <span class="hljs-string">'98%'</span>,
        <span class="hljs-attr">marginLeft</span>: <span class="hljs-number">13</span>,
        <span class="hljs-attr">marginTop</span>: theme.spacing(<span class="hljs-number">3</span>)
    },
    <span class="hljs-attr">toolbar</span>: theme.mixins.toolbar,
    <span class="hljs-attr">root</span>: {
        <span class="hljs-attr">minWidth</span>: <span class="hljs-number">470</span>
    },
    <span class="hljs-attr">bullet</span>: {
        <span class="hljs-attr">display</span>: <span class="hljs-string">'inline-block'</span>,
        <span class="hljs-attr">margin</span>: <span class="hljs-string">'0 2px'</span>,
        <span class="hljs-attr">transform</span>: <span class="hljs-string">'scale(0.8)'</span>
    },
    <span class="hljs-attr">pos</span>: {
        <span class="hljs-attr">marginBottom</span>: <span class="hljs-number">12</span>
    },
    <span class="hljs-attr">uiProgess</span>: {
        <span class="hljs-attr">position</span>: <span class="hljs-string">'fixed'</span>,
        <span class="hljs-attr">zIndex</span>: <span class="hljs-string">'1000'</span>,
        <span class="hljs-attr">height</span>: <span class="hljs-string">'31px'</span>,
        <span class="hljs-attr">width</span>: <span class="hljs-string">'31px'</span>,
        <span class="hljs-attr">left</span>: <span class="hljs-string">'50%'</span>,
        <span class="hljs-attr">top</span>: <span class="hljs-string">'35%'</span>
    },
    <span class="hljs-attr">dialogeStyle</span>: {
        <span class="hljs-attr">maxWidth</span>: <span class="hljs-string">'50%'</span>
    },
    <span class="hljs-attr">viewRoot</span>: {
        <span class="hljs-attr">margin</span>: <span class="hljs-number">0</span>,
        <span class="hljs-attr">padding</span>: theme.spacing(<span class="hljs-number">2</span>)
    },
    <span class="hljs-attr">closeButton</span>: {
        <span class="hljs-attr">position</span>: <span class="hljs-string">'absolute'</span>,
        <span class="hljs-attr">right</span>: theme.spacing(<span class="hljs-number">1</span>),
        <span class="hljs-attr">top</span>: theme.spacing(<span class="hljs-number">1</span>),
        <span class="hljs-attr">color</span>: theme.palette.grey[<span class="hljs-number">500</span>]
    }
});
</code></pre>
<p>We will add the transition for the pop up dialogue box:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> Transition = React.forwardRef(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Transition</span>(<span class="hljs-params">props, ref</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Slide</span> <span class="hljs-attr">direction</span>=<span class="hljs-string">"up"</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{ref}</span> {<span class="hljs-attr">...props</span>} /&gt;</span></span>;
});
</code></pre>
<p>Remove the existing todo class and copy-paste the following class:</p>
<pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">todo</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span> </span>{
    <span class="hljs-keyword">constructor</span>(props) {
        <span class="hljs-built_in">super</span>(props);

        <span class="hljs-built_in">this</span>.state = {
            <span class="hljs-attr">todos</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">title</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">body</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">todoId</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">errors</span>: [],
            <span class="hljs-attr">open</span>: <span class="hljs-literal">false</span>,
            <span class="hljs-attr">uiLoading</span>: <span class="hljs-literal">true</span>,
            <span class="hljs-attr">buttonType</span>: <span class="hljs-string">''</span>,
            <span class="hljs-attr">viewOpen</span>: <span class="hljs-literal">false</span>
        };

        <span class="hljs-built_in">this</span>.deleteTodoHandler = <span class="hljs-built_in">this</span>.deleteTodoHandler.bind(<span class="hljs-built_in">this</span>);
        <span class="hljs-built_in">this</span>.handleEditClickOpen = <span class="hljs-built_in">this</span>.handleEditClickOpen.bind(<span class="hljs-built_in">this</span>);
        <span class="hljs-built_in">this</span>.handleViewOpen = <span class="hljs-built_in">this</span>.handleViewOpen.bind(<span class="hljs-built_in">this</span>);
    }

    handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        <span class="hljs-built_in">this</span>.setState({
            [event.target.name]: event.target.value
        });
    };

    componentWillMount = <span class="hljs-function">() =&gt;</span> {
        authMiddleWare(<span class="hljs-built_in">this</span>.props.history);
        <span class="hljs-keyword">const</span> authToken = <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'AuthToken'</span>);
        axios.defaults.headers.common = { <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`<span class="hljs-subst">${authToken}</span>`</span> };
        axios
            .get(<span class="hljs-string">'/todos'</span>)
            .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
                <span class="hljs-built_in">this</span>.setState({
                    <span class="hljs-attr">todos</span>: response.data,
                    <span class="hljs-attr">uiLoading</span>: <span class="hljs-literal">false</span>
                });
            })
            .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
                <span class="hljs-built_in">console</span>.log(err);
            });
    };

    deleteTodoHandler(data) {
        authMiddleWare(<span class="hljs-built_in">this</span>.props.history);
        <span class="hljs-keyword">const</span> authToken = <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'AuthToken'</span>);
        axios.defaults.headers.common = { <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`<span class="hljs-subst">${authToken}</span>`</span> };
        <span class="hljs-keyword">let</span> todoId = data.todo.todoId;
        axios
            .delete(<span class="hljs-string">`todo/<span class="hljs-subst">${todoId}</span>`</span>)
            .then(<span class="hljs-function">() =&gt;</span> {
                <span class="hljs-built_in">window</span>.location.reload();
            })
            .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
                <span class="hljs-built_in">console</span>.log(err);
            });
    }

    handleEditClickOpen(data) {
        <span class="hljs-built_in">this</span>.setState({
            <span class="hljs-attr">title</span>: data.todo.title,
            <span class="hljs-attr">body</span>: data.todo.body,
            <span class="hljs-attr">todoId</span>: data.todo.todoId,
            <span class="hljs-attr">buttonType</span>: <span class="hljs-string">'Edit'</span>,
            <span class="hljs-attr">open</span>: <span class="hljs-literal">true</span>
        });
    }

    handleViewOpen(data) {
        <span class="hljs-built_in">this</span>.setState({
            <span class="hljs-attr">title</span>: data.todo.title,
            <span class="hljs-attr">body</span>: data.todo.body,
            <span class="hljs-attr">viewOpen</span>: <span class="hljs-literal">true</span>
        });
    }

    render() {
        <span class="hljs-keyword">const</span> DialogTitle = withStyles(styles)(<span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
            <span class="hljs-keyword">const</span> { children, classes, onClose, ...other } = props;
            <span class="hljs-keyword">return</span> (
                <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">MuiDialogTitle</span> <span class="hljs-attr">disableTypography</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.root}</span> {<span class="hljs-attr">...other</span>}&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"h6"</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
                    {onClose ? (
                        <span class="hljs-tag">&lt;<span class="hljs-name">IconButton</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"close"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.closeButton}</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClose}</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">CloseIcon</span> /&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">IconButton</span>&gt;</span>
                    ) : null}
                <span class="hljs-tag">&lt;/<span class="hljs-name">MuiDialogTitle</span>&gt;</span></span>
            );
        });

        <span class="hljs-keyword">const</span> DialogContent = withStyles(<span class="hljs-function">(<span class="hljs-params">theme</span>) =&gt;</span> ({
            <span class="hljs-attr">viewRoot</span>: {
                <span class="hljs-attr">padding</span>: theme.spacing(<span class="hljs-number">2</span>)
            }
        }))(MuiDialogContent);

        dayjs.extend(relativeTime);
        <span class="hljs-keyword">const</span> { classes } = <span class="hljs-built_in">this</span>.props;
        <span class="hljs-keyword">const</span> { open, errors, viewOpen } = <span class="hljs-built_in">this</span>.state;

        <span class="hljs-keyword">const</span> handleClickOpen = <span class="hljs-function">() =&gt;</span> {
            <span class="hljs-built_in">this</span>.setState({
                <span class="hljs-attr">todoId</span>: <span class="hljs-string">''</span>,
                <span class="hljs-attr">title</span>: <span class="hljs-string">''</span>,
                <span class="hljs-attr">body</span>: <span class="hljs-string">''</span>,
                <span class="hljs-attr">buttonType</span>: <span class="hljs-string">''</span>,
                <span class="hljs-attr">open</span>: <span class="hljs-literal">true</span>
            });
        };

        <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
            authMiddleWare(<span class="hljs-built_in">this</span>.props.history);
            event.preventDefault();
            <span class="hljs-keyword">const</span> userTodo = {
                <span class="hljs-attr">title</span>: <span class="hljs-built_in">this</span>.state.title,
                <span class="hljs-attr">body</span>: <span class="hljs-built_in">this</span>.state.body
            };
            <span class="hljs-keyword">let</span> options = {};
            <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.state.buttonType === <span class="hljs-string">'Edit'</span>) {
                options = {
                    <span class="hljs-attr">url</span>: <span class="hljs-string">`/todo/<span class="hljs-subst">${<span class="hljs-built_in">this</span>.state.todoId}</span>`</span>,
                    <span class="hljs-attr">method</span>: <span class="hljs-string">'put'</span>,
                    <span class="hljs-attr">data</span>: userTodo
                };
            } <span class="hljs-keyword">else</span> {
                options = {
                    <span class="hljs-attr">url</span>: <span class="hljs-string">'/todo'</span>,
                    <span class="hljs-attr">method</span>: <span class="hljs-string">'post'</span>,
                    <span class="hljs-attr">data</span>: userTodo
                };
            }
            <span class="hljs-keyword">const</span> authToken = <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'AuthToken'</span>);
            axios.defaults.headers.common = { <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`<span class="hljs-subst">${authToken}</span>`</span> };
            axios(options)
                .then(<span class="hljs-function">() =&gt;</span> {
                    <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">open</span>: <span class="hljs-literal">false</span> });
                    <span class="hljs-built_in">window</span>.location.reload();
                })
                .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
                    <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">open</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">errors</span>: error.response.data });
                    <span class="hljs-built_in">console</span>.log(error);
                });
        };

        <span class="hljs-keyword">const</span> handleViewClose = <span class="hljs-function">() =&gt;</span> {
            <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">viewOpen</span>: <span class="hljs-literal">false</span> });
        };

        <span class="hljs-keyword">const</span> handleClose = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
            <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">open</span>: <span class="hljs-literal">false</span> });
        };

        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.state.uiLoading === <span class="hljs-literal">true</span>) {
            <span class="hljs-keyword">return</span> (
                <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.content}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.toolbar}</span> /&gt;</span>
                    {this.state.uiLoading &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">CircularProgress</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{150}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.uiProgess}</span> /&gt;</span>}
                <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
            );
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> (
                <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.content}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.toolbar}</span> /&gt;</span>

                    <span class="hljs-tag">&lt;<span class="hljs-name">IconButton</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.floatingButton}</span>
                        <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span>
                        <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Add Todo"</span>
                        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClickOpen}</span>
                    &gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">AddCircleIcon</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">fontSize:</span> <span class="hljs-attr">60</span> }} /&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">IconButton</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Dialog</span> <span class="hljs-attr">fullScreen</span> <span class="hljs-attr">open</span>=<span class="hljs-string">{open}</span> <span class="hljs-attr">onClose</span>=<span class="hljs-string">{handleClose}</span> <span class="hljs-attr">TransitionComponent</span>=<span class="hljs-string">{Transition}</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">AppBar</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.appBar}</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Toolbar</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">IconButton</span> <span class="hljs-attr">edge</span>=<span class="hljs-string">"start"</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"inherit"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClose}</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"close"</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">CloseIcon</span> /&gt;</span>
                                <span class="hljs-tag">&lt;/<span class="hljs-name">IconButton</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"h6"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.title}</span>&gt;</span>
                                    {this.state.buttonType === 'Edit' ? 'Edit Todo' : 'Create a new Todo'}
                                <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
                                    <span class="hljs-attr">autoFocus</span>
                                    <span class="hljs-attr">color</span>=<span class="hljs-string">"inherit"</span>
                                    <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleSubmit}</span>
                                    <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.submitButton}</span>
                                &gt;</span>
                                    {this.state.buttonType === 'Edit' ? 'Save' : 'Submit'}
                                <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Toolbar</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">AppBar</span>&gt;</span>

                        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.form}</span> <span class="hljs-attr">noValidate</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">container</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">{2}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                        <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                        <span class="hljs-attr">required</span>
                                        <span class="hljs-attr">fullWidth</span>
                                        <span class="hljs-attr">id</span>=<span class="hljs-string">"todoTitle"</span>
                                        <span class="hljs-attr">label</span>=<span class="hljs-string">"Todo Title"</span>
                                        <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span>
                                        <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"todoTitle"</span>
                                        <span class="hljs-attr">helperText</span>=<span class="hljs-string">{errors.title}</span>
                                        <span class="hljs-attr">value</span>=<span class="hljs-string">{this.state.title}</span>
                                        <span class="hljs-attr">error</span>=<span class="hljs-string">{errors.title</span> ? <span class="hljs-attr">true</span> <span class="hljs-attr">:</span> <span class="hljs-attr">false</span>}
                                        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                    /&gt;</span>
                                <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                        <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
                                        <span class="hljs-attr">required</span>
                                        <span class="hljs-attr">fullWidth</span>
                                        <span class="hljs-attr">id</span>=<span class="hljs-string">"todoDetails"</span>
                                        <span class="hljs-attr">label</span>=<span class="hljs-string">"Todo Details"</span>
                                        <span class="hljs-attr">name</span>=<span class="hljs-string">"body"</span>
                                        <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"todoDetails"</span>
                                        <span class="hljs-attr">multiline</span>
                                        <span class="hljs-attr">rows</span>=<span class="hljs-string">{25}</span>
                                        <span class="hljs-attr">rowsMax</span>=<span class="hljs-string">{25}</span>
                                        <span class="hljs-attr">helperText</span>=<span class="hljs-string">{errors.body}</span>
                                        <span class="hljs-attr">error</span>=<span class="hljs-string">{errors.body</span> ? <span class="hljs-attr">true</span> <span class="hljs-attr">:</span> <span class="hljs-attr">false</span>}
                                        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.handleChange}</span>
                                        <span class="hljs-attr">value</span>=<span class="hljs-string">{this.state.body}</span>
                                    /&gt;</span>
                                <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Dialog</span>&gt;</span>

                    <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">container</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">{2}</span>&gt;</span>
                        {this.state.todos.map((todo) =&gt; (
                            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span> <span class="hljs-attr">sm</span>=<span class="hljs-string">{6}</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Card</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.root}</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">CardContent</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"h5"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">"h2"</span>&gt;</span>
                                            {todo.title}
                                        <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.pos}</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"textSecondary"</span>&gt;</span>
                                            {dayjs(todo.createdAt).fromNow()}
                                        <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"body2"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">"p"</span>&gt;</span>
                                            {`${todo.body.substring(0, 65)}`}
                                        <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">CardContent</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">CardActions</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"small"</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> this.handleViewOpen({ todo })}&gt;
                                            {' '}
                                            View{' '}
                                        <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"small"</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> this.handleEditClickOpen({ todo })}&gt;
                                            Edit
                                        <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"small"</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> this.deleteTodoHandler({ todo })}&gt;
                                            Delete
                                        <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">CardActions</span>&gt;</span>
                                <span class="hljs-tag">&lt;/<span class="hljs-name">Card</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
                        ))}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>

                    <span class="hljs-tag">&lt;<span class="hljs-name">Dialog</span>
                        <span class="hljs-attr">onClose</span>=<span class="hljs-string">{handleViewClose}</span>
                        <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"customized-dialog-title"</span>
                        <span class="hljs-attr">open</span>=<span class="hljs-string">{viewOpen}</span>
                        <span class="hljs-attr">fullWidth</span>
                        <span class="hljs-attr">classes</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">paperFullWidth:</span> <span class="hljs-attr">classes.dialogeStyle</span> }}
                    &gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">DialogTitle</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"customized-dialog-title"</span> <span class="hljs-attr">onClose</span>=<span class="hljs-string">{handleViewClose}</span>&gt;</span>
                            {this.state.title}
                        <span class="hljs-tag">&lt;/<span class="hljs-name">DialogTitle</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">DialogContent</span> <span class="hljs-attr">dividers</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
                                <span class="hljs-attr">fullWidth</span>
                                <span class="hljs-attr">id</span>=<span class="hljs-string">"todoDetails"</span>
                                <span class="hljs-attr">name</span>=<span class="hljs-string">"body"</span>
                                <span class="hljs-attr">multiline</span>
                                <span class="hljs-attr">readonly</span>
                                <span class="hljs-attr">rows</span>=<span class="hljs-string">{1}</span>
                                <span class="hljs-attr">rowsMax</span>=<span class="hljs-string">{25}</span>
                                <span class="hljs-attr">value</span>=<span class="hljs-string">{this.state.body}</span>
                                <span class="hljs-attr">InputProps</span>=<span class="hljs-string">{{</span>
                                    <span class="hljs-attr">disableUnderline:</span> <span class="hljs-attr">true</span>
                                }}
                            /&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">DialogContent</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Dialog</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
            );
        }
    }
}
</code></pre>
<p>At the end of this file add the following export:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> withStyles(styles)(todo);
</code></pre>
<p>First we will understand how our UI works and after that we will understand the code. Go to the browser and you'll get the following UI:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/TodoDashboard.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Todo Dashboard</em></p>
<p>Click on the Add button at the bottom right corner and you’ll get the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/AddTodo.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Add Todo</em></p>
<p>Add the Todo title and details and press the submit button. You’ll get the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/Added-Todo.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Todo Dashboard</em></p>
<p>After this click on the view button and you’ll be able to see the full details of the Todo:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/View-Todo.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>View Single Todo</em></p>
<p>Click on the Edit button and you’ll be able to edit the todo:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/EditTodo.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Edit Todo</em></p>
<p>Click the delete button and you’ll be able to delete the Todo. Now as we are aware of how Dashboard works, we will understand the components used in it.</p>
<p><strong>1. Add Todo:</strong> For implementing the add todo we will use the <a target="_blank" href="https://material-ui.com/components/dialogs/#full-screen-dialogs">Dialogue component</a> of Material UI. This component implements a hook functionality. We are using the classes so we will remove that functionality.</p>
<pre><code class="lang-js"><span class="hljs-comment">// This sets the state to open and buttonType flag to add:</span>
<span class="hljs-keyword">const</span> handleClickOpen = <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">this</span>.setState({
           <span class="hljs-attr">todoId</span>: <span class="hljs-string">''</span>,
           <span class="hljs-attr">title</span>: <span class="hljs-string">''</span>,
           <span class="hljs-attr">body</span>: <span class="hljs-string">''</span>,
           <span class="hljs-attr">buttonType</span>: <span class="hljs-string">''</span>,
           <span class="hljs-attr">open</span>: <span class="hljs-literal">true</span>
     });
};

<span class="hljs-comment">// This sets the state to close:</span>
<span class="hljs-keyword">const</span> handleClose = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">open</span>: <span class="hljs-literal">false</span> });
};
</code></pre>
<p>Other than this we will also change the placement of the Add Todo Button.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Position our button</span>
<span class="hljs-attr">floatingButton</span>: {
    <span class="hljs-attr">position</span>: <span class="hljs-string">'fixed'</span>,
    <span class="hljs-attr">bottom</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">right</span>: <span class="hljs-number">0</span>
},

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">IconButton</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.floatingButton}</span> <span class="hljs-attr">...</span> &gt;</span></span>
</code></pre>
<p>Now we will replace the list tag with a form inside this Dialogue. It will help us in adding the new todo.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Show Edit or Save depending on buttonType state</span>
{<span class="hljs-built_in">this</span>.state.buttonType === <span class="hljs-string">'Edit'</span> ? <span class="hljs-string">'Save'</span> : <span class="hljs-string">'Submit'</span>}

<span class="hljs-comment">// Our Form to add a todo</span>
&lt;form className={classes.form} noValidate&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">container</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">{2}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span>&gt;</span>
        // TextField here
        <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span>&gt;</span>
        // TextField here
        <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span></span>
&lt;/form&gt;
</code></pre>
<p>The handleSubmit consists of logic to read the <code>buttonType</code> state. If the state is an empty string <code>(“”)</code> then it will post on the Add Todo API. If the state is an <code>Edit</code> then in that scenario it will update the Edit Todo.</p>
<p><strong>2. Get Todos:</strong> To display the todos we will use the <code>Grid container</code> and inside it, we place the <code>Grid item</code> . Inside that, we will use a <code>Card</code> component to display the data.</p>
<pre><code class="lang-js">&lt;Grid container spacing={<span class="hljs-number">2</span>}&gt;
    {<span class="hljs-built_in">this</span>.state.todos.map(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span> <span class="hljs-attr">sm</span>=<span class="hljs-string">{6}</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Card</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.root}</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">CardContent</span>&gt;</span>
        // Here will show Todo with view, edit and delete button
        <span class="hljs-tag">&lt;/<span class="hljs-name">CardContent</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Card</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span></span>))}
&lt;/Grid&gt;
</code></pre>
<p>We use the map to display the todo item as the API sends them in a list. We will use the componentWillMount lifecycle to get and set the state before the render is executed. There are 3 buttons ( <strong>view, edit, and delete</strong> ) so we will need 3 Handlers to handle the operation when the button is clicked. We will learn about these buttons in their respective subsections.</p>
<p><strong>3. Edit Todo:</strong> For the edit todo, we are reusing the dialogue pop up code that is used in add todo. To differentiate between the button clicks we are using a <code>buttonType</code> state. For Add Todo the <code>buttonType</code> state is <code>(“”)</code> while for edit todo it is <code>Edit</code>.</p>
<pre><code class="lang-js">handleEditClickOpen(data) {
    <span class="hljs-built_in">this</span>.setState({
        ..,
        <span class="hljs-attr">buttonType</span>: <span class="hljs-string">'Edit'</span>,
        ..
    });
}
</code></pre>
<p>In the <code>handleSubmit</code> method we read the <code>buttonType</code> state and then send the request accordingly.</p>
<p><strong>4. Delete Todo:</strong> When this button is clicked we send the todo object to our deleteTodoHandler and then it sends the request further to the backend.</p>
<pre><code class="lang-js">&lt;Button size=<span class="hljs-string">"small"</span> onClick={<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">this</span>.deleteTodoHandler({ todo })}&gt;Delete&lt;/Button&gt;
</code></pre>
<p><strong>5. View Todo:</strong> When showing the data we have truncated it so that the user will get a glimpse of what the todo is about. But if a user wants to know more about it then they need to click on the view button.</p>
<p>For this, we will use the <a target="_blank" href="https://material-ui.com/components/dialogs/#customized-dialogs">Customised dialogue</a>. Inside that, we use DialogTitle and DialogContent. It displays our title and content. In DialougeContent we will use the form to display the content that the user has posted. (This is one solution that I found there are many and you are free to try other.)</p>
<pre><code class="lang-js"><span class="hljs-comment">// This is used to remove the underline of the Form</span>
InputProps={{
       <span class="hljs-attr">disableUnderline</span>: <span class="hljs-literal">true</span>
}}

<span class="hljs-comment">// This is used so that user cannot edit the data</span>
readonly
</code></pre>
<p><strong>6. Applying Theme:</strong> This is the last step of our application. We will apply a theme on our application. For this we are using <code>createMuiTheme</code> and <code>ThemeProvider</code> from material UI. Copy-paste the following code in <code>App.js</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { ThemeProvider <span class="hljs-keyword">as</span> MuiThemeProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/styles'</span>;
<span class="hljs-keyword">import</span> createMuiTheme <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/styles/createMuiTheme'</span>;

<span class="hljs-keyword">const</span> theme = createMuiTheme({
    <span class="hljs-attr">palette</span>: {
        <span class="hljs-attr">primary</span>: {
            <span class="hljs-attr">light</span>: <span class="hljs-string">'#33c9dc'</span>,
            <span class="hljs-attr">main</span>: <span class="hljs-string">'#FF5722'</span>,
            <span class="hljs-attr">dark</span>: <span class="hljs-string">'#d50000'</span>,
            <span class="hljs-attr">contrastText</span>: <span class="hljs-string">'#fff'</span>
        }
    }
});

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">MuiThemeProvider</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span>&gt;</span>
        // Router and switch will be here.
        <span class="hljs-tag">&lt;/<span class="hljs-name">MuiThemeProvider</span>&gt;</span></span>
    );
}
</code></pre>
<p>We missed applying a theme to our button in <code>todo.js</code> in the <code>CardActions</code> . Add the color tag for the view, edit, and delete button.</p>
<pre><code class="lang-js">&lt;Button size=<span class="hljs-string">"small"</span> color=<span class="hljs-string">"primary"</span> ...&gt;
</code></pre>
<p>Go to the browser and you will find that everything is the same except that the app is a different color.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/FinalTodo.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>TodoApp after applying theme</em></p>
<p>And we're done! We have built a TodoApp using ReactJS and Firebase. If you have built it all the way to this point then a very big congratulations to you on this achievement.</p>
<blockquote>
<p>Feel free to connect with me on <a target="_blank" href="https://twitter.com/sharvinshah26">Twitter</a> and <a target="_blank" href="https://github.com/Sharvin26">Github</a>.</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Firebase Cloud Messaging Integration for Cordova Hybrid Apps ]]>
                </title>
                <description>
                    <![CDATA[ By t1tan1um This is a basic straight forward walk through regarding how to implement push notification in Android as well as iOS using the cordova plugin for fcm and Google Firebase FCM from scratch. I will be using Ubuntu 16.04 LTS for this, but OS ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/firebase-cloud-messaging-integration-for-cordova-hybrid-apps/</link>
                <guid isPermaLink="false">66c34a7130aba6677fb9f991</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Cloud Computing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Firebase ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sat, 18 Jan 2020 19:13:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9dc2740569d1a4ca397b.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By t1tan1um</p>
<p>This is a basic straight forward walk through regarding how to implement push notification in Android as well as iOS using the <a target="_blank" href="https://github.com/fechanique/cordova-plugin-fcm">cordova plugin for fcm</a> and Google Firebase FCM from scratch. I will be using Ubuntu 16.04 LTS for this, but OS used for development should not matter much.</p>
<h2 id="heading-fcm-integration-for-cordova-hybrid-apps"><strong>FCM Integration for Cordova Hybrid Apps</strong></h2>
<h3 id="heading-android-implementation"><strong>Android Implementation</strong></h3>
<p>Create an empty folder pushSample</p>
<pre><code class="lang-text">cd '/opt/lampp/htdocs'
mkdir pushSample
cd pushSample
cordova create pushSample
cd pushSample
cordova platform add android
cordova plugin add cordova-plugin-FCM
</code></pre>
<p>While adding the cordova FCM plugin will show an error :</p>
<pre><code class="lang-text">Error: cordova-plugin-fcm: You have installed platform android but file 'google-services.json' was not found in your Cordova project root folder.
</code></pre>
<p>Note : This is because we have not added the google-services.json file which has to be created in the next following steps.</p>
<p>Next open the <a target="_blank" href="https://console.firebase.google.com/">google firebase console</a> and Add Project ( basically means create a new project )</p>
<p>Once the project is created click on the Notifications section in the left side panel.</p>
<p>Now click on the Android icon to add <strong>Android</strong> platform support to our project.</p>
<p>In the next popup form fill the details as follows : <strong>Android package name :</strong> Package name or ID is the unique identifier for an app in the play store. Note that it is a very important value which cannot be changed for an app once it is uploaded to the play store. It will be in reverse domain name syntax : eg hello.pushSample.com will have app id : com.pushSample.hello. Also in the <strong>config.xml</strong> file in your cordova project set the same app id. For our sample project it will be in : pushSample/pushSample/config.xml eg for me the contents of this file are :</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;?xml version='1.0' encoding='utf-8'?&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">widget</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"io.cordova.hellocordova"</span> <span class="hljs-attr">version</span>=<span class="hljs-string">"1.0.0"</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/ns/widgets"</span> <span class="hljs-attr">xmlns:cdv</span>=<span class="hljs-string">"http://cordova.apache.org/ns/1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>HelloCordova<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">description</span>&gt;</span>
        A sample Apache Cordova application that responds to the deviceready event.
    <span class="hljs-tag">&lt;/<span class="hljs-name">description</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">author</span> <span class="hljs-attr">email</span>=<span class="hljs-string">"dev@cordova.apache.org"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"http://cordova.io"</span>&gt;</span>
        Apache Cordova Team
    <span class="hljs-tag">&lt;/<span class="hljs-name">author</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">content</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"index.html"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"cordova-plugin-whitelist"</span> <span class="hljs-attr">spec</span>=<span class="hljs-string">"1"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">access</span> <span class="hljs-attr">origin</span>=<span class="hljs-string">"*"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">allow-intent</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"http://*/*"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">allow-intent</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://*/*"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">allow-intent</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"tel:*"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">allow-intent</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"sms:*"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">allow-intent</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"mailto:*"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">allow-intent</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"geo:*"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">platform</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"android"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">allow-intent</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"market:*"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">platform</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">platform</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"ios"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">allow-intent</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"itms:*"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">allow-intent</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"itms-apps:*"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">platform</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">widget</span>&gt;</span>
</code></pre>
<p>Note the tag</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">widget</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"io.cordova.hellocordova"</span> <span class="hljs-attr">version</span>=<span class="hljs-string">"1.0.0"</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/ns/widgets"</span> <span class="hljs-attr">xmlns:cdv</span>=<span class="hljs-string">"http://cordova.apache.org/ns/1.0"</span>&gt;</span>
</code></pre>
<p>Here the attribute id is the package <strong>id</strong> which will by default be <strong>io.cordova.hellocordova</strong> change it to the app ID you have specified in the firebase console. I will be using com.pushSample.hello</p>
<p>Next field to be filled in the firebase console popup is :</p>
<p><strong>App nickname (optional) :</strong> This can be the same app name which is displayed in the menu for the app, this can also be changed in the config.xml, by default it will be HelloCordova, i will update it to <strong>PushSample</strong></p>
<p><strong>Debug signing certificate SHA-1 (optional) :</strong> This is optional please leave it blank.</p>
<p>Next click on <strong>Register App</strong></p>
<p>Next step is to download the <strong>google services json</strong> file.</p>
<p><img src="https://preview.ibb.co/nEjbwv/1_Wje_TClf8o9z_Dxw3_W_wkpw.png" alt="download google services json" width="600" height="400" loading="lazy"></p>
<p>Click on the <strong>Download google-services.json</strong> button, which should download the file to your PC.</p>
<p>Once you get the file paste it in the root folder of your cordova project, in my case :</p>
<pre><code class="lang-text">/opt/lampp/htdocs/pushSample/pushSample
</code></pre>
<p>Next build the project</p>
<pre><code class="lang-text">cordova build android
</code></pre>
<p>After adding the google-services.json file it should build successfully.</p>
<p>Next we have to write the client side code for handling push notifications :</p>
<pre><code class="lang-js">FCMPlugin.getToken(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">token</span>) </span>{
    <span class="hljs-comment">//this is the FCM token which can be used</span>
    <span class="hljs-comment">//to send notification to specific device </span>
    <span class="hljs-built_in">console</span>.log(token);
    <span class="hljs-comment">//FCMPlugin.onNotification( onNotificationCallback(data), successCallback(msg), errorCallback(err) )</span>
    <span class="hljs-comment">//Here you define your application behaviour based on the notification data.</span>
    FCMPlugin.onNotification(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>) </span>{
        <span class="hljs-built_in">console</span>.log(data);
        <span class="hljs-comment">//data.wasTapped == true means in Background :  Notification was received on device tray and tapped by the user.</span>
        <span class="hljs-comment">//data.wasTapped == false means in foreground :  Notification was received in foreground. Maybe the user needs to be notified.</span>
        <span class="hljs-comment">// if (data.wasTapped) {</span>
        <span class="hljs-comment">//     //Notification was received on device tray and tapped by the user.</span>
        <span class="hljs-comment">//     alert(JSON.stringify(data));</span>
        <span class="hljs-comment">// } else {</span>
        <span class="hljs-comment">//     //Notification was received in foreground. Maybe the user needs to be notified.</span>
        <span class="hljs-comment">//     alert(JSON.stringify(data));</span>
        <span class="hljs-comment">// }</span>
    });
});
</code></pre>
<p>The code basically first calls the <strong>getToken</strong> function to get an FCM token from firebase, then in the callback registers another callback <strong>onNotification</strong> to handle what happens when a push notification is received.</p>
<p>the <strong>onNotification</strong> function has a data value which contains the notification data. data.wasTapped indicates whether the notification is sent when the app is in foreground or background, so that we can define separate logic for each case. Now to trigger a sample push notification click on the Notification section in the left side panel, this should now show you the firebase notification composer, showing the list of past notifications sent.</p>
<p>In case you have not sent any push notifications yet. You should see a <strong>send your first notification</strong> button.</p>
<p><strong>Note:</strong> The Notification Composer will look like this :</p>
<p><img src="https://preview.ibb.co/b4qc3a/1_s_W2_Ad_QJz_JEFjto6rz1_8r_A.png" alt="send your first notification" width="600" height="400" loading="lazy"></p>
<p>Note While sending push notification using firebase console you need to select app name <strong>com.pushSample.hello</strong> in my case.</p>
<p>To send the custom application specific data select advance options -&gt; Key value pairs.</p>
<p><img src="https://preview.ibb.co/ensbUF/1_qp9_Mz_XBZvn_PYawyo0_TQBRA.png" alt="advanced options" width="600" height="400" loading="lazy"></p>
<p>The data object in the onNotification callback will look as follows</p>
<pre><code class="lang-js">{<span class="hljs-attr">myKey2</span>: <span class="hljs-string">"valuefor2"</span>, <span class="hljs-attr">myKey</span>: <span class="hljs-string">"valuefor1"</span>, <span class="hljs-attr">wasTapped</span>: <span class="hljs-literal">false</span>}
</code></pre>
<p>Also note while sending push notifications using REST APIs from your app server instead of the firebase notification composer, you have to use the following syntax :</p>
<pre><code class="lang-js"><span class="hljs-comment">//POST: https://fcm.googleapis.com/fcm/send</span>
<span class="hljs-comment">//HEADER: Content-Type: application/json</span>
<span class="hljs-comment">//HEADER: Authorization: key=AIzaSy*******************</span>
{
  <span class="hljs-string">"notification"</span>:{
    <span class="hljs-string">"title"</span>:<span class="hljs-string">"Notification title"</span>,
    <span class="hljs-string">"body"</span>:<span class="hljs-string">"Notification body"</span>,
    <span class="hljs-string">"sound"</span>:<span class="hljs-string">"default"</span>,
    <span class="hljs-string">"click_action"</span>:<span class="hljs-string">"FCM_PLUGIN_ACTIVITY"</span>,
    <span class="hljs-string">"icon"</span>:<span class="hljs-string">"fcm_push_icon"</span>
  },
  <span class="hljs-string">"data"</span>:{
    <span class="hljs-string">"param1"</span>:<span class="hljs-string">"value1"</span>,
    <span class="hljs-string">"param2"</span>:<span class="hljs-string">"value2"</span>
  },
    <span class="hljs-string">"to"</span>:<span class="hljs-string">"/topics/topicExample"</span>,
    <span class="hljs-string">"priority"</span>:<span class="hljs-string">"high"</span>,
    <span class="hljs-string">"restricted_package_name"</span>:<span class="hljs-string">""</span>
}
<span class="hljs-comment">//sound: optional field if you want sound with the notification</span>
<span class="hljs-comment">//click_action: must be present with the specified value for Android</span>
<span class="hljs-comment">//icon: white icon resource name for Android &gt;5.0</span>
<span class="hljs-comment">//data: put any "param":"value" and retreive them in the JavaScript notification callback</span>
<span class="hljs-comment">//to: device token or /topic/topicExample</span>
<span class="hljs-comment">//priority: must be set to "high" for delivering notifications on closed iOS apps</span>
<span class="hljs-comment">//restricted_package_name: optional field if you want to send only to a restricted app package (i.e: com.myapp.test)</span>
</code></pre>
<p><strong>Note : “click_action”:”FCM_PLUGIN_ACTIVITY”</strong> field is very important as not mentioning it will not execute the onNotification callback in foreground mode.</p>
<p><img src="https://image.ibb.co/gRS1UF/0_QIzc_JZH9_Nqzpjygg.jpg" alt="done with android implementation" width="600" height="400" loading="lazy"></p>
<h3 id="heading-ios-implementation"><strong>iOS Implementation</strong></h3>
<p>For the iOS implementation we will require the following things to be generated in the <a target="_blank" href="https://developer.apple.com/">apple developer page.</a> I am using XCODE 8.3</p>
<p>App ID : com.example.app Apple Push Notification Authentication Key ( APNs Auth Key ) Development Provisioning Profile with Push Notifications Enabled. APNs Certificates</p>
<p>Also <a target="_blank" href="https://firebase.google.com/docs/cloud-messaging/ios/client">Firebase docs for push notifications</a> is an excellent in depth starting point.</p>
<p>Note: You cannot run push notifications in the simulator, you will need an actual device.</p>
<p>Lets begin.</p>
<p>Firstly login to firebase developer’s console, and select an existing project or create a new project, we will be using the same pushSample project. In the project overview add another app with iOS as platform. In the popup that comes up, enter the following details :</p>
<ul>
<li>Step 1 <strong>Bundle id :</strong> this is the unique identifier which is used to identify an app in the apple appstore, this should be same as the bundle id you will specify in the config.xml file of the cordova project or the Bundle Id section in xCode. we will use <strong>com.pushSample.hello</strong> <strong>App Name</strong> : This is the option identifier nick name, we will be using the same name which will display in the iOS app menu which is PushSample. <strong>App Store Id</strong> : Leave this blank.</li>
</ul>
<p>Once you click on register app the iOS app step 2 appears.</p>
<ul>
<li>Step 2 Here click on the download <strong>Googleservice-info.plist</strong> button to download the file which we will use in the later steps.</li>
</ul>
<p><strong>Step3 and Step 4</strong> we can skip as these will be handled internally by the cordova FCM plugin.</p>
<p>Once the iOS app is added to your project Click on the gear icon besides the overview label in the left side panel and select project settings. ( Refer below image. ) . This should by default open the General Tab of your project settings.</p>
<p><img src="https://preview.ibb.co/ddcwwv/1_c_Pee_Xdmf76l_W0_YRr_I83_Log.png" alt="Project Settings" width="600" height="400" loading="lazy"></p>
<p>Next click on your iOS app in Your Apps -&gt; iOS Apps. In the iOS app details update the <strong>App ID Prefix</strong>, the value for which you will get in the Apple Member Center under the membership tab.</p>
<p>Now switch to the <strong>Cloud Messaging</strong> tab -&gt; iOS app configuration section.</p>
<p><img src="https://preview.ibb.co/m2Ktbv/1_0p_Vvf_JGYb_TEUIhwr_DIek_Q.png" alt="cloud messaging" width="600" height="400" loading="lazy"></p>
<p>Here as discussed earlier upload the APNs Auth Key you generated in the Apple member center. Next we do the client side app setup. Create a new folder sampleApp in your development folder, for me it is</p>
<pre><code class="lang-text">/Volumes/Development/
</code></pre>
<p>so the new folder will be</p>
<pre><code class="lang-text">/Volumes/Development/pushSample
cd /Volumes/Development/pushSample
</code></pre>
<p>Create a new cordova project, <strong>Note : Use sudo if required</strong></p>
<pre><code class="lang-text">cordova create pushSample
cd pushSample
</code></pre>
<p>Now add the latest iOS platform</p>
<pre><code class="lang-text">sudo cordova platform add ios
</code></pre>
<p>Now paste the <strong>Googleservice-info.plist</strong> file we downloaded earlier in the cordova project root folder, for me it is</p>
<pre><code class="lang-text">/Volumes/Development/pushSample/pushSample
</code></pre>
<p>add the cordova fcm plugin.</p>
<pre><code class="lang-text">cordova plugin add cordova-plugin-fcm
</code></pre>
<p>Update the default app id and app name with the bundle id we decided earlier while configuring firebase console and the app name.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">widget</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"com.pushSample.hello"</span> <span class="hljs-attr">version</span>=<span class="hljs-string">"1.0.0"</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/ns/widgets"</span> <span class="hljs-attr">xmlns:cdv</span>=<span class="hljs-string">"http://cordova.apache.org/ns/1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>PushSample<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span>
</code></pre>
<p>At this point the sample code will have an app.js file, which you can modify and add the getToken and onNotification functions same as android. The javascript code is same for both platforms.</p>
<p>Next run cordova build command</p>
<pre><code class="lang-text">sudo cordova build ios
</code></pre>
<p>Once the cordova build command is successful, open the app in xcode. To do this open the xcode.proj file, which will be located in</p>
<pre><code class="lang-text">your_cordova_project/platforms/ios/app_name.xcodeproj
</code></pre>
<p>for me it is</p>
<pre><code class="lang-text">/Volumes/Development/pushSample/pushSample/platforms/ios/PushSample.xcodeproj
</code></pre>
<p><img src="https://preview.ibb.co/hePLOa/1_Xe_Kh4_VXU_o_BQ05_UGRa_B6_A.png" alt="Xcode Project" width="600" height="400" loading="lazy"></p>
<p>Next enable Push Notifications in the Capabilities Tab of the project.</p>
<p>Connect an actual device and run the app.</p>
<p>Now trigger the push notification from the firebase notification composer and everything should work…</p>
<p><img src="https://image.ibb.co/jz8VOa/1vnhjv.jpg" alt="happy steve" width="600" height="400" loading="lazy"></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to build an Angular 8 app from scratch in 11 easy steps ]]>
                </title>
                <description>
                    <![CDATA[ By Ahmed Bouchefra Angular is one of the three most popular frameworks for front-end development, alongside React and Vue.js. The latest version is Angular 8 which was released on May 28, 2019.  There are many new features and enhancements to both th... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/angular-8-tutorial-in-easy-steps/</link>
                <guid isPermaLink="false">66d45d5cb3016bf139028d07</guid>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                    <category>
                        <![CDATA[ angular8 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 11 Nov 2019 22:31:27 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/12/desktop-cropped-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Ahmed Bouchefra</p>
<p>Angular is one of the three most popular frameworks for front-end development, alongside React and Vue.js. The latest version is Angular 8 which was released on May 28, 2019. </p>
<p>There are many new features and enhancements to both the command-line interface and the framework itself which result in a performance-boost and smaller production bundles. One interesting feature is the ng deploy command which allows developers to quickly build and deploy their Angular apps to popular hosting providers such as Firebase or GitHub.</p>
<p>In this tutorial, we’ll take you step by step on a journey to build an example Angular application from scratch that uses many Angular APIs such as HttpClient, and Material Design.</p>
<p>Here are a few things we'll learn:</p>
<ul>
<li>How to mock a REST API server that uses fake data from a JSON file </li>
<li>How to consume the REST API from our Angular 8 application using  <code>Httplient</code></li>
<li>How to handle HTTP errors using the RxJS  <code>throwError()</code>  and  <code>catchError()</code>  operators</li>
<li>How to retry failed HTTP requests in poor network conditions and cancel pending requests using the RxJS  <code>retry()</code>  and  <code>takeUntil()</code> operators</li>
<li>How to create and make use of Angular components and services </li>
<li>How to set up routing and Angular Material in our project and create a professional-looking UI with Material Design components</li>
<li>And finally, we’ll learn how to deploy the application to Firebase using the  <code>ng deploy</code>  command available in Angular 8.3+.</li>
</ul>
<p>You’ll also learn by example:</p>
<ul>
<li>How to quickly mock a REST API with real-world features, such as pagination, that you can consume from your app before you can switch to a real backend when it’s ready.</li>
<li>How to set up Angular CLI</li>
<li>How to initialize your Angular 8 project</li>
<li>How to set up Angular Material</li>
<li>How to add Angular components and routing</li>
<li>How to generate and use Angular services</li>
<li>How to consume REST APIs with Angular HttpClient</li>
<li>How to build and deploy your Angular application to Firebase.</li>
</ul>
<p>This tutorial is divided into the following steps:</p>
<ul>
<li>Step 1 — Installing Angular CLI 8</li>
<li>Step 2 — Creating your Angular 8 Project</li>
<li>Step 3 — Adding Angular HttpClient</li>
<li>Step 4 — Creating Components</li>
<li>Step 5 — Adding Routing</li>
<li>Step 6 — Building the UI with Angular Material Components</li>
<li>Step 7 — Mocking a REST API</li>
<li>Step 8 — Consuming the REST API with Angular HttpClient</li>
<li>Step 9 — Handling HTTP Errors</li>
<li>Step 10 — Adding Pagination</li>
<li>Step 11 — Building and Deploying your Angular Application to Firebase</li>
</ul>
<p>Now, let’s get started with the prerequisites!</p>
<blockquote>
<p><strong>Note</strong>: you can download our <strong><a target="_blank" href="https://www.techiediaries.com/angular-book-build-your-first-web-apps/">Angular 8 Book: Build your first web apps with Angular 8</a> </strong> for free.</p>
</blockquote>
<h1 id="heading-prerequisites">Prerequisites</h1>
<p>If you want to follow this tutorial, you’ll need to have:</p>
<ul>
<li>Prior knowledge of TypeScript.</li>
<li>A development machine with  <strong>Node 8.9+</strong> and  <strong>NPM 5.5.1+</strong>  installed. Node is required by the Angular CLI. You can head to <a target="_blank" href="https://nodejs.org/downloads">the official website</a> and grab the binaries for your system. You can also use  <a target="_blank" href="https://github.com/nvm-sh/nvm">NVM</a>  — Node Version Manager — a POSIX-compliant bash script to install and manage multiple Node.js versions in your machine.</li>
</ul>
<p>If you are ready, let’s learn by example how to build an Angular 8 application that consumes a REST API using HttpClient. We'll implement real-world features like error handling and retrying failed HTTP requests.</p>
<h1 id="heading-step-1-installing-angular-cli-8">Step 1 — Installing Angular CLI 8</h1>
<p>Let’s start with the first step, where we’ll install the latest version of Angular CLI.</p>
<p><img src="https://www.techiediaries.com/ezoimgfmt/www.diigo.com/file/image/rscqpoqzoceeaeedqzdspasasb/Angular+CLI+8.jpg?ezimgfmt=rs:461x281/rscb1/ng:webp/ngcb1" alt="Image" width="600" height="400" loading="lazy"></p>
<p><a target="_blank" href="https://cli.angular.io/">Angular CLI</a>  is the official tool for initializing and working with Angular projects. Head to a new terminal and execute the following command:</p>
<pre><code class="lang-bash">$ npm install -g @angular/cli
</code></pre>
<p>When writing this tutorial,  <strong>angular/cli v8.3.2</strong>  is installed on our system.</p>
<p>That’s it, you are ready for the second step!</p>
<h1 id="heading-step-2-creating-your-angular-8-project">Step 2 — Creating your Angular 8 Project</h1>
<p>In this step, we’ll use Angular CLI to initialize our Angular project.</p>
<p>Go to your terminal and execute these commands:</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> ~  
$ ng new angular-example
</code></pre>
<p>The CLI will prompt you and ask <strong>whether you would like to add Angular routing.</strong> Say Yes. It'll then ask <strong>which stylesheet format you would like to use.</strong> Choose <strong>CSS</strong>.</p>
<p>Angular CLI will generate the required files and folders, install the packages from npm, and even automatically set up routing in our project.</p>
<p>Now, go to your project’s root folder and run the local development server using these commands:</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> angular-example  
$ ng serve
</code></pre>
<p>Your Angular web application will be available from the  <code>[http://localhost:4200/](http://localhost:4200/)</code>  address.</p>
<p><img src="https://www.techiediaries.com/ezoimgfmt/www.diigo.com/file/image/rscqpoqzoceeaposbzdspascea/Angular+CLI+Ng+Serve.jpg?ezimgfmt=rs:710x191/rscb1/ng:webp/ngcb1" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Open a web browser and go to the  <code>http://localhost:4200/</code> address. You should see this beautiful page (Starting with Angular 8.3+):</p>
<p><img src="https://www.techiediaries.com/ezoimgfmt/paper-attachments.dropbox.com/s_F52E295BB9C92BEFE7506DFCE2086C2583C762072AFE2CA1A9CE9AD4DA9FF751_1567465432228_Angulardemo.png?ezimgfmt=rs:710x341/rscb1/ng:webp/ngcb1" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You need to leave the development server running and open a new terminal for the next steps.</p>
<p>You are now ready for the third step!</p>
<h1 id="heading-step-3-adding-angular-httpclient">Step 3 — Adding Angular HttpClient</h1>
<p>In this step, we’ll add  <code>HttpClient</code>  to our example project.</p>
<p>Open the  <code>src/app/app.module.ts</code>  file and make the following changes:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { BrowserModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/platform-browser'</span>;
<span class="hljs-keyword">import</span> { NgModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;

<span class="hljs-keyword">import</span> { AppRoutingModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app-routing.module'</span>;
<span class="hljs-keyword">import</span> { AppComponent } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.component'</span>;
<span class="hljs-keyword">import</span> { HttpClientModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/common/http'</span>;

<span class="hljs-meta">@NgModule</span>({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule { }
</code></pre>
<p>We simply imported <a target="_blank" href="https://angular.io/api/common/http/HttpClientModule#description">HttpClientModule</a> and included it in the <code>imports</code> array.</p>
<p>That’s all - now we can use the  <code>HttpClient</code>  service in our Angular project to consume our REST API.</p>
<p>You are ready for the fifth step!</p>
<h1 id="heading-step-4-creating-ui-components">Step 4 — Creating UI Components</h1>
<p>Angular apps are made up of components. In this step, we’ll learn how to create a couple of Angular components that compose our UI.</p>
<p>Open a new terminal and run the following command:</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> ~/angular-example  
$ ng g component home
</code></pre>
<p>You’ll get the following output in your terminal:</p>
<pre><code>CREATE src/app/home/home.component.html (<span class="hljs-number">19</span> bytes)  
CREATE src/app/home/home.component.spec.ts (<span class="hljs-number">614</span> bytes)  
CREATE src/app/home/home.component.ts (<span class="hljs-number">261</span> bytes)  
CREATE src/app/home/home.component.css (<span class="hljs-number">0</span> bytes)  
UPDATE src/app/app.module.ts (<span class="hljs-number">467</span> bytes)
</code></pre><p>We have four files, all required by our component.</p>
<p>Next, generate the about component:</p>
<pre><code class="lang-bash">$ ng g component about
</code></pre>
<p>Next, open the  <code>src/app/about/about.component.html</code>  file and add the following code:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"padding: 15px;"</span>&gt;</span> This is the about page that describes your app<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>You are ready for the sixth step!</p>
<h1 id="heading-step-5-adding-routing">Step 5 — Adding Routing</h1>
<p>In this step, we’ll learn how to add routing to our example.</p>
<p>Go to the  <code>src/app/app-routing.module.ts</code>  file and add the following routes:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { NgModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { Routes, RouterModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/router'</span>;
<span class="hljs-keyword">import</span> { HomeComponent } <span class="hljs-keyword">from</span> <span class="hljs-string">'./home/home.component'</span>;
<span class="hljs-keyword">import</span> { AboutComponent } <span class="hljs-keyword">from</span> <span class="hljs-string">'./about/about.component'</span>;


<span class="hljs-keyword">const</span> routes: Routes = [
  { path: <span class="hljs-string">''</span>, redirectTo: <span class="hljs-string">'home'</span>, pathMatch: <span class="hljs-string">'full'</span>},
  { path: <span class="hljs-string">'home'</span>, component: HomeComponent },
  { path: <span class="hljs-string">'about'</span>, component: AboutComponent },
];

<span class="hljs-meta">@NgModule</span>({
  imports: [RouterModule.forRoot(routes)],
  <span class="hljs-built_in">exports</span>: [RouterModule]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppRoutingModule { }
</code></pre>
<p>We imported the Angular components and we declared three routes.</p>
<p>The first route is for redirecting the empty path to the home component, so we’ll be automatically redirected to the home page when we first visit the app.</p>
<p>That’s it. Now that you have added routing, you are ready for the next step!</p>
<h1 id="heading-step-6-adding-angular-material">Step 6 — Adding Angular Material</h1>
<p>In this tutorial step, we’ll learn to set up <a target="_blank" href="https://material.angular.io/">Angular Material</a> in our project and build our application UI using Material components.</p>
<p>Go to your terminal and run this command from the root of your project:</p>
<pre><code class="lang-bash">$ ng add @angular/material
</code></pre>
<p>You’ll be prompted to choose the theme, so let’s pick <strong>Indigo/Pink</strong>.</p>
<p>For the other questions - whether you want to <strong>set up HammerJS for gesture recognition</strong> and if you want to <strong>set up browser animations for Angular Material</strong> - press <strong>Enter</strong> to use the default answers.</p>
<p>Open the  <code>src/app/app.module.ts</code>  file and add the following imports:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { MatToolbarModule,
  MatIconModule,
  MatCardModule,
  MatButtonModule,
  MatProgressSpinnerModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/material'</span>;
</code></pre>
<p>We imported the modules for these Material Design components:</p>
<ul>
<li><a target="_blank" href="https://material.angular.io/components/toolbar/overview">MatToolbar</a> that provides a container for headers, titles, or actions.</li>
<li><a target="_blank" href="https://material.angular.io/components/card/overview">MatCard</a> that provides a content container for text, photos, and actions in the context of a single subject.</li>
<li><a target="_blank" href="https://material.angular.io/components/button/overview">MatButton</a> that provides a native  <code>&lt;button&gt;</code>  or  <code>&lt;a&gt;</code>  element enhanced with Material Design styling and ink ripples.</li>
<li><a target="_blank" href="https://material.angular.io/components/progress-spinner/overview">MatProgressSpinner</a> that provides a circular indicator of progress and activity.</li>
</ul>
<p>Next, add these modules to the  <code>imports</code>  array:</p>
<pre><code class="lang-ts"><span class="hljs-meta">@NgModule</span>({
  declarations: [
    AppComponent,
    HomeComponent,
    AboutComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    BrowserAnimationsModule,
    MatToolbarModule,
    MatIconModule,
    MatButtonModule,
    MatCardModule,
    MatProgressSpinnerModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule { }
</code></pre>
<p>Next, open the  <code>src/app/app.component.html</code>  file and update it as follows:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">mat-toolbar</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>  
My Angular Store  
<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">mat-button</span> <span class="hljs-attr">routerLink</span>=<span class="hljs-string">"/"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">mat-button</span> <span class="hljs-attr">routerLink</span>=<span class="hljs-string">"/about"</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">mat-toolbar</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">router-outlet</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">router-outlet</span>&gt;</span>
</code></pre>
<p>We added a top navigation bar with two buttons that take us to the home and about pages, respectively.</p>
<h1 id="heading-step-7-mocking-a-rest-api">Step 7 — Mocking a REST API</h1>
<p>Go to a new command-line interface and start by installing  <code>json-server</code>  from npm in your project:</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> ~/angular-example
$ npm install --save json-server
</code></pre>
<p>Next, create a  <code>server</code>  folder in the root folder of your Angular project:</p>
<pre><code class="lang-bash">$ mkdir server
$ <span class="hljs-built_in">cd</span> server
</code></pre>
<p>In the  <code>server</code>  folder, create a  <code>database.json</code>  file and add the following JSON object:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"products"</span>: []
}
</code></pre>
<p>This JSON file will act as a database for your REST API server. You can simply add some data to be served by your REST API or use <a target="_blank" href="https://github.com/marak/Faker.js/">Faker.js</a> for automatically generating massive amounts of realistic fake data.</p>
<p>Go back to your command-line, navigate back from the  <code>server</code>  folder, and install <code>Faker.js</code>  from npm using the following command:</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> ..
$ npm install faker --save
</code></pre>
<p>At the time of creating this example, <strong>faker v4.1.0</strong> will be installed.</p>
<p>Now, create a  <code>generate.js</code>  file and add the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">var</span> faker = <span class="hljs-built_in">require</span>(<span class="hljs-string">'faker'</span>);

<span class="hljs-keyword">var</span> database = { <span class="hljs-attr">products</span>: []};

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">1</span>; i&lt;= <span class="hljs-number">300</span>; i++) {
  database.products.push({
    <span class="hljs-attr">id</span>: i,
    <span class="hljs-attr">name</span>: faker.commerce.productName(),
    <span class="hljs-attr">description</span>: faker.lorem.sentences(),
    <span class="hljs-attr">price</span>: faker.commerce.price(),
    <span class="hljs-attr">imageUrl</span>: <span class="hljs-string">"https://source.unsplash.com/1600x900/?product"</span>,
    <span class="hljs-attr">quantity</span>: faker.random.number()
  });
}

<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">JSON</span>.stringify(database));
</code></pre>
<p>We first imported faker, and next we defined an object with one empty array for products. Next, we entered a <em>for</em> loop to create <em>300</em> fake entries using faker methods like  <code>faker.commerce.productName()</code>  for generating product names. <a target="_blank" href="https://github.com/marak/Faker.js/#api-methods">Check all the available methods</a>. Finally we converted the database object to a string and logged it to standard output.</p>
<p>Next, add the  <code>generate</code>  and  <code>server</code>  scripts to the  <code>package.json</code>  file:</p>
<pre><code class="lang-json">  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"ng"</span>: <span class="hljs-string">"ng"</span>,
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"ng serve"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"ng build"</span>,
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"ng test"</span>,
    <span class="hljs-attr">"lint"</span>: <span class="hljs-string">"ng lint"</span>,
    <span class="hljs-attr">"e2e"</span>: <span class="hljs-string">"ng e2e"</span>,
    <span class="hljs-attr">"generate"</span>: <span class="hljs-string">"node ./server/generate.js &gt; ./server/database.json"</span>,
    <span class="hljs-attr">"server"</span>: <span class="hljs-string">"json-server --watch ./server/database.json"</span>
  },
</code></pre>
<p>Next, head back to your command-line interface and run the generate script using the following command:</p>
<pre><code class="lang-bash">$ npm run generate
</code></pre>
<p>Finally, run the REST API server by executing the following command:</p>
<pre><code class="lang-bash">$ npm run server
</code></pre>
<p>You can now send HTTP requests to the server just like any typical REST API server. Your server will be available from the  <code>http://localhost:3000/</code>  address.</p>
<p>These are the API endpoints we'll be able to use via our JSON REST API server:</p>
<ul>
<li><code>GET /products</code>  for getting the products</li>
<li><code>GET /products/&lt;id&gt;</code>  for getting a single product by id</li>
<li><code>POST /products</code>  for creating a new product</li>
<li><code>PUT /products/&lt;id&gt;</code>  for updating a product by id</li>
<li><code>PATCH /products/&lt;id&gt;</code>  for partially updating a product by id</li>
<li><code>DELETE /products/&lt;id&gt;</code>  for deleting a product by id</li>
</ul>
<p>You can use  <code>_page</code>  and  <code>_limit</code>  parameters to get paginated data. In the  <code>Link</code> header you'll get  <code>first</code>,  <code>prev</code>,  <code>next</code>  and  <code>last</code>  links.</p>
<p>Leave the JSON REST API server running and open a new command-line interface for typing the commands of the next steps.</p>
<h1 id="heading-step-8-creating-a-service-for-consuming-the-rest-api-with-angular-httpclient">Step 8 — Creating a Service for Consuming the REST API with Angular HttpClient</h1>
<p>In this step, we’ll learn how to consume our REST API from Angular using HttpClient.</p>
<p>We’ll need to create an Angular service for encapsulating the code that allows us to consume data from our REST API server.</p>
<p>Go to your terminal and run the following command:</p>
<pre><code class="lang-bash">$ ng g service api
</code></pre>
<p>Next, go to the  <code>src/app/api.service.ts</code>  file, import and inject  <code>HttpClient</code>:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { HttpClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/common/http'</span>;

<span class="hljs-meta">@Injectable</span>({
  providedIn: <span class="hljs-string">'root'</span>
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ApiService {

  <span class="hljs-keyword">private</span> SERVER_URL = <span class="hljs-string">"http://localhost:3000"</span>;

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> httpClient: HttpClient</span>) { }
}
</code></pre>
<p>We imported and injected the  <code>HttpClient</code>  service and defined the  <code>SERVER_URL</code> variable that contains the address of our REST API server.</p>
<p>Next, define a  <code>get()</code>  method that sends a GET request to the REST API endpoint:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;  
<span class="hljs-keyword">import</span> { HttpClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/common/http'</span>;

<span class="hljs-meta">@Injectable</span>({  
    providedIn: <span class="hljs-string">'root'</span>  
})  
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ApiService {

    <span class="hljs-keyword">private</span> SERVER_URL = <span class="hljs-string">"http://localhost:3000"</span>;
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> httpClient: HttpClient</span>) { }

    <span class="hljs-keyword">public</span> get(){  
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.httpClient.get(<span class="hljs-built_in">this</span>.SERVER_URL);  
    }  
}
</code></pre>
<p>The method simply invokes the  <code>get()</code>  method of  <code>HttpClient</code>  to send GET requests to the REST API server.</p>
<p>Next, we now need to use this service in our home component. Open the <code>src/app/home/home.component.ts</code>  file, and import and inject the data service as follows:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { Component, OnInit } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;  
<span class="hljs-keyword">import</span> { ApiService } <span class="hljs-keyword">from</span> <span class="hljs-string">'../api.service'</span>;

<span class="hljs-meta">@Component</span>({  
    selector: <span class="hljs-string">'app-home'</span>,  
    templateUrl: <span class="hljs-string">'./home.component.html'</span>,  
    styleUrls: [<span class="hljs-string">'./home.component.css'</span>]  
})  
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> HomeComponent <span class="hljs-keyword">implements</span> OnInit {
    products = [];
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> apiService: ApiService</span>) { }
    ngOnInit() {
        <span class="hljs-built_in">this</span>.apiService.get().subscribe(<span class="hljs-function">(<span class="hljs-params">data: <span class="hljs-built_in">any</span>[]</span>)=&gt;</span>{  
            <span class="hljs-built_in">console</span>.log(data);  
            <span class="hljs-built_in">this</span>.products = data;  
        })  
    }
}
</code></pre>
<p>We imported and injected  <code>ApiService.</code>  Next, we defined a  <code>products</code>  variable and called the  <code>get()</code>  method of the service for fetching data from the JSON REST API server.</p>
<p>Next, open the  <code>src/app/home/home.component.html</code>  file and update it as follows:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"padding: 13px;"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">mat-spinner</span> *<span class="hljs-attr">ngIf</span>=<span class="hljs-string">"products.length === 0"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">mat-spinner</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span> *<span class="hljs-attr">ngFor</span>=<span class="hljs-string">"let product of products"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"margin-top:10px;"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-header</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-title</span>&gt;</span>{{product.name}}<span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-title</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-subtitle</span>&gt;</span>{{product.price}} $/ {{product.quantity}}
            <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-subtitle</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-header</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-content</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
                {{product.description}}
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"height:100%; width: 100%;"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"{{ product.imageUrl }}"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-content</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-actions</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">mat-button</span>&gt;</span> Buy product<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-actions</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>We used the  <code>&lt;mat-spinner&gt;</code>  component for showing a loading spinner when the length of the  <code>products</code>  array equals zero, that is before any data is received from the REST API server.</p>
<p>Next, we iterated over the  <code>products</code>  array and used a Material card to display the <code>name</code>,  <code>price</code>,  <code>quantity</code>,  <code>description</code>  and  <code>image</code>  of each product.</p>
<p>This is a screenshot of the home page after JSON data is fetched:</p>
<p><img src="https://miro.medium.com/max/301/0*R7qs5jGg_IlOtTWF" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Next, we’ll see how to add error handling to our service.</p>
<h1 id="heading-step-9-adding-error-handling">Step 9 — Adding Error Handling</h1>
<p>In this step, we’ll learn to add error handling in our example.</p>
<p>Go to the  <code>src/app/api.service.ts</code>  file and update it as follows:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { HttpClient, HttpErrorResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"@angular/common/http"</span>;

<span class="hljs-keyword">import</span> {  throwError } <span class="hljs-keyword">from</span> <span class="hljs-string">'rxjs'</span>;
<span class="hljs-keyword">import</span> { retry, catchError } <span class="hljs-keyword">from</span> <span class="hljs-string">'rxjs/operators'</span>;


<span class="hljs-meta">@Injectable</span>({
  providedIn: <span class="hljs-string">'root'</span>
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ApiService {

  <span class="hljs-keyword">private</span> SERVER_URL = <span class="hljs-string">"http://localhost:3000/products"</span>;

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> httpClient: HttpClient</span>) { }

  handleError(error: HttpErrorResponse) {
    <span class="hljs-keyword">let</span> errorMessage = <span class="hljs-string">'Unknown error!'</span>;
    <span class="hljs-keyword">if</span> (error.error <span class="hljs-keyword">instanceof</span> ErrorEvent) {
      <span class="hljs-comment">// Client-side errors</span>
      errorMessage = <span class="hljs-string">`Error: <span class="hljs-subst">${error.error.message}</span>`</span>;
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-comment">// Server-side errors</span>
      errorMessage = <span class="hljs-string">`Error Code: <span class="hljs-subst">${error.status}</span>\nMessage: <span class="hljs-subst">${error.message}</span>`</span>;
    }
    <span class="hljs-built_in">window</span>.alert(errorMessage);
    <span class="hljs-keyword">return</span> throwError(errorMessage);
  }

  <span class="hljs-keyword">public</span> sendGetRequest(){
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.httpClient.get(<span class="hljs-built_in">this</span>.SERVER_URL).pipe(catchError(<span class="hljs-built_in">this</span>.handleError));
  }
}
</code></pre>
<p>This is a screenshot of an example error on the browser console:</p>
<p><img src="https://miro.medium.com/max/442/0*gZUHzXPjrRSSK4ZF" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In the next step, we’ll see how to add pagination to our application</p>
<h1 id="heading-step-10-adding-pagination">Step 10 — Adding Pagination</h1>
<p>In this step, we’ll learn to add support for data pagination using the Link header of the HTTP response received from the REST API server.</p>
<p>By default, HttpClient provides only the response body. But in our app we need to parse the Link header for extracting pagination links. So we need to instruct<code>HttpClient</code>  to give us the full <a target="_blank" href="https://angular.io/api/common/http/HttpResponse">HttpResponse</a> using the  <code>observe</code>  option.</p>
<p>The Link header in HTTP allows the server to point an interested client to another resource containing metadata about the requested resource. <a target="_blank" href="https://www.w3.org/wiki/LinkHeader">Wikipedia</a></p>
<p>Open the <code>src/app/data.service.ts</code> file and import the RxJS  <code>tap()</code>  operator:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { retry, catchError, tap } <span class="hljs-keyword">from</span> <span class="hljs-string">'rxjs/operators'</span>;
</code></pre>
<p>Next, add these variables:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">public</span> first: <span class="hljs-built_in">string</span> = <span class="hljs-string">""</span>;  
<span class="hljs-keyword">public</span> prev: <span class="hljs-built_in">string</span> = <span class="hljs-string">""</span>;  
<span class="hljs-keyword">public</span> next: <span class="hljs-built_in">string</span> = <span class="hljs-string">""</span>;  
<span class="hljs-keyword">public</span> last: <span class="hljs-built_in">string</span> = <span class="hljs-string">""</span>;
</code></pre>
<p>Next, add the  <code>parseLinkHeader()</code>  method that will be used to parse the Link header and populates the previous variables:</p>
<pre><code class="lang-ts">  parseLinkHeader(header) {
    <span class="hljs-keyword">if</span> (header.length == <span class="hljs-number">0</span>) {
      <span class="hljs-keyword">return</span> ;
    }

    <span class="hljs-keyword">let</span> parts = header.split(<span class="hljs-string">','</span>);
    <span class="hljs-keyword">var</span> links = {};
    parts.forEach( <span class="hljs-function"><span class="hljs-params">p</span> =&gt;</span> {
      <span class="hljs-keyword">let</span> section = p.split(<span class="hljs-string">';'</span>);
      <span class="hljs-keyword">var</span> url = section[<span class="hljs-number">0</span>].replace(<span class="hljs-regexp">/&lt;(.*)&gt;/</span>, <span class="hljs-string">'$1'</span>).trim();
      <span class="hljs-keyword">var</span> name = section[<span class="hljs-number">1</span>].replace(<span class="hljs-regexp">/rel="(.*)"/</span>, <span class="hljs-string">'$1'</span>).trim();
      links[name] = url;

    });

    <span class="hljs-built_in">this</span>.first  = links[<span class="hljs-string">"first"</span>];
    <span class="hljs-built_in">this</span>.last   = links[<span class="hljs-string">"last"</span>];
    <span class="hljs-built_in">this</span>.prev   = links[<span class="hljs-string">"prev"</span>];
    <span class="hljs-built_in">this</span>.next   = links[<span class="hljs-string">"next"</span>]; 
  }
</code></pre>
<p>Next, update the  <code>sendGetRequest()</code>  as follows:</p>
<pre><code class="lang-ts">  <span class="hljs-keyword">public</span> sendGetRequest(){
    <span class="hljs-comment">// Add safe, URL encoded _page and _limit parameters </span>

    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.httpClient.get(<span class="hljs-built_in">this</span>.SERVER_URL, {  params: <span class="hljs-keyword">new</span> HttpParams({fromString: <span class="hljs-string">"_page=1&amp;_limit=20"</span>}), observe: <span class="hljs-string">"response"</span>}).pipe(retry(<span class="hljs-number">3</span>), catchError(<span class="hljs-built_in">this</span>.handleError), tap(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(res.headers.get(<span class="hljs-string">'Link'</span>));
      <span class="hljs-built_in">this</span>.parseLinkHeader(res.headers.get(<span class="hljs-string">'Link'</span>));
    }));
  }
</code></pre>
<p>We added the  <code>observe</code>  option with the  <code>response</code>  value in the options parameter of the  <code>get()</code>  method so we can have the full HTTP response with headers. Next, we use the RxJS  <code>tap()</code>  operator for parsing the Link header before returning the final Observable.</p>
<p>Since the  <code>sendGetRequest()</code>  is now returning an Observable with a full HTTP response, we need to update the home component so open the  <code>src/app/home/home.component.ts</code>  file and import  <code>HttpResponse</code>  as follows:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { HttpResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/common/http'</span>;
</code></pre>
<p>Next, update the  <code>subscribe()</code>  method as follows:</p>
<pre><code class="lang-ts">ngOnInit(){

<span class="hljs-built_in">this</span>.apiService.sendGetRequest().pipe(takeUntil(<span class="hljs-built_in">this</span>.destroy$)).subscribe(<span class="hljs-function">(<span class="hljs-params">res: HttpResponse&lt;<span class="hljs-built_in">any</span>&gt;</span>)=&gt;</span>{  
    <span class="hljs-built_in">console</span>.log(res);  
    <span class="hljs-built_in">this</span>.products = res.body;  
})  
}
</code></pre>
<p>We can now access the data from the  <code>body</code>  object of the received HTTP response.</p>
<p>Next, go back to the src/app/data.service.ts file and add the following method:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">public</span> sendGetRequestToUrl(url: <span class="hljs-built_in">string</span>){  
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.httpClient.get(url, { observe: <span class="hljs-string">"response"</span>}).pipe(retry(<span class="hljs-number">3</span>),             
    catchError(<span class="hljs-built_in">this</span>.handleError), tap(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {  
        <span class="hljs-built_in">console</span>.log(res.headers.get(<span class="hljs-string">'Link'</span>));  
        <span class="hljs-built_in">this</span>.parseLinkHeader(res.headers.get(<span class="hljs-string">'Link'</span>));
    }));  
}
</code></pre>
<p>This method is similar to  <code>sendGetRequest()</code>  except that it takes the URL to which we need to send an HTTP GET request.</p>
<p>Go back to the  <code>src/app/home/home.component.ts</code>  file and add define the following methods:</p>
<pre><code class="lang-ts"> <span class="hljs-keyword">public</span> firstPage() {
    <span class="hljs-built_in">this</span>.products = [];
    <span class="hljs-built_in">this</span>.apiService.sendGetRequestToUrl(<span class="hljs-built_in">this</span>.apiService.first).pipe(takeUntil(<span class="hljs-built_in">this</span>.destroy$)).subscribe(<span class="hljs-function">(<span class="hljs-params">res: HttpResponse&lt;<span class="hljs-built_in">any</span>&gt;</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(res);
      <span class="hljs-built_in">this</span>.products = res.body;
    })
  }
  <span class="hljs-keyword">public</span> previousPage() {

    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.apiService.prev !== <span class="hljs-literal">undefined</span> &amp;&amp; <span class="hljs-built_in">this</span>.apiService.prev !== <span class="hljs-string">''</span>) {
      <span class="hljs-built_in">this</span>.products = [];
      <span class="hljs-built_in">this</span>.apiService.sendGetRequestToUrl(<span class="hljs-built_in">this</span>.apiService.prev).pipe(takeUntil(<span class="hljs-built_in">this</span>.destroy$)).subscribe(<span class="hljs-function">(<span class="hljs-params">res: HttpResponse&lt;<span class="hljs-built_in">any</span>&gt;</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(res);
        <span class="hljs-built_in">this</span>.products = res.body;
      })
    }

  }
  <span class="hljs-keyword">public</span> nextPage() {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.apiService.next !== <span class="hljs-literal">undefined</span> &amp;&amp; <span class="hljs-built_in">this</span>.apiService.next !== <span class="hljs-string">''</span>) {
      <span class="hljs-built_in">this</span>.products = [];
      <span class="hljs-built_in">this</span>.apiService.sendGetRequestToUrl(<span class="hljs-built_in">this</span>.apiService.next).pipe(takeUntil(<span class="hljs-built_in">this</span>.destroy$)).subscribe(<span class="hljs-function">(<span class="hljs-params">res: HttpResponse&lt;<span class="hljs-built_in">any</span>&gt;</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(res);
        <span class="hljs-built_in">this</span>.products = res.body;
      })
    }
  }
  <span class="hljs-keyword">public</span> lastPage() {
    <span class="hljs-built_in">this</span>.products = [];
    <span class="hljs-built_in">this</span>.apiService.sendGetRequestToUrl(<span class="hljs-built_in">this</span>.apiService.last).pipe(takeUntil(<span class="hljs-built_in">this</span>.destroy$)).subscribe(<span class="hljs-function">(<span class="hljs-params">res: HttpResponse&lt;<span class="hljs-built_in">any</span>&gt;</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(res);
      <span class="hljs-built_in">this</span>.products = res.body;
    })
  }
</code></pre>
<p>Finally, open the  <code>src/app/home/home.component.html</code>  file and update the template as follows:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"padding: 13px;"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">mat-spinner</span> *<span class="hljs-attr">ngIf</span>=<span class="hljs-string">"products.length === 0"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">mat-spinner</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">mat-card</span> *<span class="hljs-attr">ngFor</span>=<span class="hljs-string">"let product of products"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"margin-top:10px;"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-header</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-title</span>&gt;</span>#{{product.id}} {{product.name}}<span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-title</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-subtitle</span>&gt;</span>{{product.price}} $/ {{product.quantity}}
            <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-subtitle</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-header</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-content</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
                {{product.description}}
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"height:100%; width: 100%;"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"{{ product.imageUrl }}"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-content</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mat-card-actions</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">mat-button</span>&gt;</span> Buy product<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card-actions</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">mat-card</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> (<span class="hljs-attr">click</span>) =<span class="hljs-string">"firstPage()"</span> <span class="hljs-attr">mat-button</span>&gt;</span> First<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> (<span class="hljs-attr">click</span>) =<span class="hljs-string">"previousPage()"</span> <span class="hljs-attr">mat-button</span>&gt;</span> Previous<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> (<span class="hljs-attr">click</span>) =<span class="hljs-string">"nextPage()"</span> <span class="hljs-attr">mat-button</span>&gt;</span> Next<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> (<span class="hljs-attr">click</span>) =<span class="hljs-string">"lastPage()"</span> <span class="hljs-attr">mat-button</span>&gt;</span> Last<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>This is a screenshot of our application:</p>
<p><img src="https://miro.medium.com/max/17/0*c_21mFswM-ZiReUi?q=20" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://miro.medium.com/max/297/0*c_21mFswM-ZiReUi" alt="Image" width="600" height="400" loading="lazy"></p>
<h1 id="heading-step-11-building-and-deploying-your-angular-application-to-firebase">Step 11 — Building and Deploying your Angular Application to Firebase</h1>
<p>Head back to your command-line interface. Make sure you are inside the root folder of your Angular project and run the following command:</p>
<pre><code class="lang-bash">$ ng add @angular/fire
</code></pre>
<p>This will add the Firebase deployment capability to your project.</p>
<p>As the time of writing this tutorial, <strong>@angular/fire v5.2.1</strong> will be installed.</p>
<p>The command will also update the  <code>package.json</code>  of our project by adding this section:</p>
<pre><code class="lang-json">        <span class="hljs-string">"deploy"</span>: {
          <span class="hljs-attr">"builder"</span>: <span class="hljs-string">"@angular/fire:deploy"</span>,
          <span class="hljs-attr">"options"</span>: {}
        }
</code></pre>
<p>The CLI will prompt you to <strong>Paste authorization code here:</strong> and will open your default web browser and ask you to give Firebase CLI permissions to administer your Firebase account.</p>
<p>After you sign in with the Google account associated with your Firebase account, you'll be given the authorization code.</p>
<p>Next, you'll be prompted to <strong>Please select a project: (Use arrow keys or type to search)</strong>. You should have created a Firebase project before.</p>
<p>The CLI will create the  <code>firebase.json</code>  and  <code>.firebaserc</code>  files and update the <code>angular.json</code>  file accordingly.</p>
<p>Next, deploy your application to Firebase using the following command:</p>
<pre><code class="lang-bash">$ ng deploy
</code></pre>
<p>The command will produce an optimized build of your application (equivalent to the <code>ng deploy --prod</code>  command). It will upload the production assets to Firebase hosting.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Throughout this step by step tutorial, you learned to build an Angular application from scratch using the latest Angular 8.3+ version.</p>
<p>You learned to mock a REST API backend for your Angular application with nearly zero lines of code.</p>
<p>You learned how to create a project using Angular CLI, add  <code>HttpClient</code>  and Angular Material for sending HTTP requests to your mocked REST API backend, and style the UI with Material Design components.</p>
<p>Finally, you learned to deploy your Angular application to Firebase using the  <code>ng deploy</code>  command available starting from Angular 8.3+.</p>
<p>Check out our other <a target="_blank" href="https://www.techiediaries.com/angular">Angular tutorials</a>.</p>
<p>You can reach out to or follow the author via his:</p>
<ul>
<li><a target="_blank" href="https://www.ahmedbouchefra.com/">Personal website</a></li>
<li><a target="_blank" href="https://twitter.com/ahmedbouchefra">Twitter</a></li>
<li><a target="_blank" href="https://www.linkedin.com/in/mr-ahmed/">LinkedIn</a></li>
<li><a target="_blank" href="https://github.com/techiediaries">Github</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How I built a desktop chat app with CometChat and NW.js (and how you can too) ]]>
                </title>
                <description>
                    <![CDATA[ This is not your typical "paste this here" and "paste that there"-type tutorial (you can find plenty of those here on cometchat.com/tutorials). While those tutorials certainly have merit, I am going to share my thought process from beginning to end. ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-i-build-a-desktop-chat-app-with-cometchat-and-nw-js-and-how-you-can-too/</link>
                <guid isPermaLink="false">66d4604633b83c4378a51808</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Chat ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Mihail Gaberov ]]>
                </dc:creator>
                <pubDate>Sun, 22 Sep 2019 11:38:05 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/09/mihail-chat-app-image.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>This is not your typical "<em>paste this here</em>" and "<em>paste that there</em>"-type tutorial (you can find plenty of those here on <a target="_blank" href="https://www.cometchat.com/tutorials/desktop-chat-app-tutorial/">cometchat.com/tutorials</a>). While those tutorials certainly have merit, I am going to share my thought process from beginning to end.</p>
<p>The application I built is simple enough. When someone loads the app, they are prompted to enter their username and begin chatting:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/image-143.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Welcome Screen</em></p>
<p>The application ultimately runs on Node with help from NW.js (previously known as node-webkit). NW.js is advantageous because it enables us to code cross-platform desktop applications using our favorite web technologies. For this application, I chose to use React and Redux.</p>
<p>The back-end logic - from sending and receiving messages in real-time to populating what I call the "participant list" - is powered by CometChat. You will learn more about <a target="_blank" href="https://cometchat.com/pro">CometChat</a> as you read on.</p>
<p>This post is not intended to be a walkthrough. Although I will be explaining the technical components of this application, my main ambition is to help you think through a solution from beginning to end. Hopefully, when you finish this post you'll be a slightly better developer and consider CometChat for your growing tool belt.</p>
<p><strong>Just want the example code?</strong></p>
<p>You may see the source code <a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw">here</a>. There is also a detailed <a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/blob/master/README.md">README</a>, where you will find all the information you need to install, run and test the app.</p>
<p>Because the desktop app is built using web technologies, it is entirely possible to run it in your browser. Towards the end of this post, I will show you how to deploy the app on Netlify.</p>
<h2 id="heading-planning"><strong>Planning</strong></h2>
<p>In this section we have to decide what components will we need to build. What functionality will they have? In other words, what are the questions we need to answer, to plan the building process?</p>
<p>Let’s step back for a while and think. Try asking yourself the questions who will take us to the structure we need for our app.</p>
<p><em>Below I am going to lay out my questions and the answers. This is the process of the actual building the structure of the app, but in your head first. Keep in mind that it happens very often such that when answering a question new questions appear. This was the case with me as well.</em></p>
<p><strong>Questions:</strong></p>
<ul>
<li><p>What am I doing? ?</p>
</li>
<li><p>What kind of app am I going to be building?</p>
</li>
<li><p>What are the most common components, such an app needs to have?</p>
</li>
<li><p>How do the app’s components interact with each other?</p>
</li>
<li><p>What level of completion am I aiming for — (demo apps are not supposed to be fully featured)?</p>
</li>
</ul>
<p><strong>Answers</strong> (following the order of the questions):</p>
<ul>
<li><p>This is the most neglected question that many people forget to think about. <em>When one can step aside first and give a clear answer to this question, his path for future developments becomes settled</em>. In my specific case the answer I got sounds something like this — “I am thinking about building a chat app. This app should serve as a tutorial demo app. It will have to provide basic functionality for ‘having a chat’ by using CometChat API. It should run on a desktop”. The styling and specific details about what goes where will come later in the process.</p>
</li>
<li><p>A chat app that will run on desktop and serve as a demo for this tutorial.</p>
</li>
<li><p>To give a proper answer to this question, a non-familiar person would have to do some research first. Take a look at real-world chat applications. Make notes of what features they have. How are they put them in place, how do they interact between them and with the users of the app. In my case, I had some <a target="_blank" href="https://mihail-gaberov.eu/how-i-build-chat-app-with-react-and-typescript-part1/">previous experience</a> and got, more or less, the idea of what I need.</p>
</li>
<li><p>The interaction between the components would be pretty straight forward. The user should be able to use the main component that is a text input and a button to send messages. And a sidebar component to see the other chat participants.</p>
</li>
<li><p>The demo app should provide basic chat functionality — send and receive real-time messages. And be able to run on a desktop (without a browser).</p>
</li>
</ul>
<h2 id="heading-features"><strong>Features</strong></h2>
<p>I have decided to implement the following features to the demo app:</p>
<ul>
<li><p>Send with Enter key</p>
</li>
<li><p>A sidebar with names and last active time</p>
</li>
<li><p>Welcome screen with input and validation with error messages</p>
</li>
<li><p>Chat area with auto-scroll to bottom</p>
</li>
<li><p>Chat message and time of sending.</p>
</li>
</ul>
<h2 id="heading-front-end-react"><strong>Front End — React</strong></h2>
<p>We are going to use <a target="_blank" href="https://reactjs.org/">React</a> to build our user interface. Below, I am going to list the components I have created and a short explanation about each of them:</p>
<ul>
<li><p><a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/tree/master/src/components/ChatPane">ChatPane</a> — this is the main container-like component that contains the Participants and Conversation components and passes the data they need to visualize.</p>
</li>
<li><p><a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/blob/master/src/components/Conversation/Conversation.jsx">Conversation</a> — this is the component responsible for typing and sending chat messages.</p>
</li>
<li><p><a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/blob/master/src/components/Footer/Footer.jsx">Footer</a> — displays a simple footer message, containing the app name and version, as defined in package.json file.</p>
</li>
<li><p><a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/blob/master/src/components/Header/Header.jsx">Header</a> — header component holding the application menu bar.</p>
</li>
<li><p><a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/blob/master/src/components/MenuAppBar/MenuAppBar.jsx">MenuAppBar</a> — application menu bar component, simulating how a real menu bar would look like. The hamburger menu on the left and the profile dropdown menu on the right are fake — clickable, but not functional.</p>
</li>
<li><p><a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/blob/master/src/components/Messages/Messages.jsx">Messages</a> — a container component, holding a message itself — it has the name of the sender, the message content and the time of sending.</p>
</li>
<li><p><a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/tree/master/src/components/Participants">Participants</a> — this component shows the name of a chat member and the time when he joined.</p>
</li>
<li><p><a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/tree/master/src/components/Welcome">Welcome</a> — this component is responsible for displaying the login page — the starting point of our app, where we have logic related to checking for certain allowed usernames and storing them to the local storage for later use. I also implemented basic error handling logic, which shows an error when the selected username is not correct, as per CometChat API (in this specific case for our demo) registered usernames — superhero1, superhero2 and so on till 5.</p>
</li>
</ul>
<p>Here a visual representation of the app components:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/image-144.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Visual Components</em></p>
<h2 id="heading-state-management-redux"><strong>State Management — Redux</strong></h2>
<p>Every modern application these days has a state. Place in the memory where the application is storing certain data for later use. For our application state management, we use <a target="_blank" href="https://redux.js.org/">Redux</a>. Of course, for a simple app like this, we could go without using Redux at all. But, from the learning point of view (<em>after all we all do this for learning new stuff, right?</em>), I think it would be nice to see the whole cycle of sending a request to an API, going through a middleware (redux-thunks) and getting the response recorded to the state. And we will manage this state by using Redux.</p>
<h3 id="heading-how-it-works"><strong>How it works</strong></h3>
<p>The main building blocks in a Redux app are called reducers — small functions used for managing the state. Simply said, what they do is accepting the old state object as input and, depending on certain actions (which are also passed in the same input), returning new state object. The new state could be changed in full or just partially.</p>
<p>In our app, we have three simple reducers, which are responsible for those parts of the state, responsible for the users’ list, the login process and sending/receiving messages. All of them can be seen in <a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/tree/master/src/reducers">/src/reducers</a> folder, along with a <a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/blob/master/src/reducers/initialState.js">file</a> containing the initial state of our app.</p>
<p>Redux, as state management library, can be used with any other UI framework, practically every app that needs to have a state can benefit from using Redux. If you want to go deeper, start from their website and follow along.</p>
<h2 id="heading-side-effects-handling-redux-thunks"><strong>Side Effects Handling — Redux Thunks</strong></h2>
<p>One of the best known approaches for managing side effects in a redux app is called <a target="_blank" href="https://github.com/reduxjs/redux-thunk">redux-think</a>. This is what we use in our application as well. If you want to learn more details about redux thunks and how to use them, I recommend their website as a starting point and then build a small application, like this one for example :).</p>
<p>In our project, in <a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/tree/master/src/actions">/src/actions folder</a>, is where I put the thunks used in the demo application. And in <a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/tree/master/src/store">/store</a> directory is where the configurations for the redux store live.</p>
<h2 id="heading-make-it-desktop-nwjs"><strong>Make it desktop — NW.js</strong></h2>
<p>The part of our application that makes it possible for our app to run on desktop is taken care of by a library called <a target="_blank" href="https://nwjs.io/">NW.js</a>. Remember that we are building a desktop application. Exactly the desktop part is going to be implemented via NW.js. Similar to <a target="_blank" href="https://electronjs.org/">Electron</a>, another library for building desktop applications, NW.js provides a way to the developers to use their web skills to build applications that can run on a desktop. This means you can still use your JavaScript/React skills when building an app and then leverage the power of the desktop operating system via Nw.js APIs. In other words, Nw.js gives you the ability to make a skeleton app, which can be “filled” with your UI, no matter what library you have used to create it. And the best thing is that such an app has access to Node.js/NW.js APIs and the DOM in the same JavaScript context.</p>
<p>Since we mentioned the other big player in the field of building cross-platform desktop apps, let me give you a brief comparison between the two.</p>
<h2 id="heading-nwjs-vs-electron"><strong>Nw.js vs Electron</strong></h2>
<p>Entry of Application</p>
<ul>
<li><p>In NW.js the main entry point of an application is a web page or a JS script. You specify an HTML or js file in the package.json and it is opened in a browser window as the application's main window (in case of an HTML entrypoint) or the script is executed.</p>
</li>
<li><p>In Electron, the entry point is a JavaScript script.</p>
</li>
</ul>
<p>Build System</p>
<ul>
<li><p>Nw.js uses Chromium</p>
</li>
<li><p>Electron uses <a target="_blank" href="https://github.com/electron/libchromiumcontent">libchromiumcontent</a> to access Chromium's Content API. libchromiumcontent is a single shared library that includes the Chromium Content module and all of its dependencies.</p>
</li>
</ul>
<p>Node Integration</p>
<ul>
<li><p>In NW.js, the Node integration in web pages requires patching Chromium to work.</p>
</li>
<li><p>In Electron uses a different way to integrate the libuv loop with each platform's message loop to avoid hacking Chromium.</p>
</li>
</ul>
<p>Multi-context</p>
<ul>
<li><p>Because of how NW.js was implemented concepts of Node context and web context were invented.</p>
</li>
<li><p>By using the <a target="_blank" href="https://github.com/nodejs/node-v0.x-archive/commit/756b622">multi-context</a> feature of Node, Electron doesn't introduce a new JavaScript context in web pages.</p>
</li>
</ul>
<h2 id="heading-chat-cometchat"><strong>Chat — CometChat</strong></h2>
<p>The usage of CometChat API is pretty straight-forward. It’s a RESTFull API, on which is built another layer of abstraction - CometChat SDK. It allows us to call directly exposed methods for different actions we might want to perform, such as send. Here an example of such a method:</p>
<pre><code class="lang-js"><span class="hljs-keyword">return</span> CometChat.sendMessage(textMessage).then(    
  <span class="hljs-function"><span class="hljs-params">message</span> =&gt;</span> {      
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Message sent successfully:"</span>, message);      
    <span class="hljs-keyword">return</span> message;
  }, 
  <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {      
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Message sending failed with error:"</span>, error);    
  }
);
</code></pre>
<p>You may see all the Chat API logic in <a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/tree/master/src/chat-api">/src/chat-api</a> folder. There you will also see the mocks I created, which allow us to test our app without real connection to the API.</p>
<h2 id="heading-improvements"><strong>Improvements</strong></h2>
<p>Every project deserves some thoughts after finishing the first phase. One part of this thought process would be dedicated to how it went, what was good and bad, and what might be done better. And one part would be dedicated to thinking about possible improvements. Here are a few ideas for our case. If someone goes to this direction and implement any of these for real, please do not forget to let me know :)</p>
<ul>
<li><p>Waiting animation for when loading the chat history and the user list</p>
</li>
<li><p>Option for skipping the login screen, if already logged</p>
</li>
<li><p>Option for sending invitations to new users</p>
</li>
<li><p>Option for seeing the status of a message — sent, received, read</p>
</li>
<li><p>Emojis support</p>
</li>
<li><p>Inline links/images/video support, such that the user can see them interpreted — playing video, rendered image or web page to which a link is pointing. I have added these as <a target="_blank" href="https://github.com/mihailgaberov/desktop-chat-nw/issues">issues in my GitHub</a>, in case anyone wants to take a look.</p>
</li>
</ul>
<h2 id="heading-deploy-on-netlify"><strong>Deploy on Netlify</strong></h2>
<p>To deploy your application to Netlify platform you need to create an account first. Go to <a target="_blank" href="https://www.netlify.com/">their website</a> and sign up for new account. After that go ahead and login. While still under Sites section, you should see a button for deploying new site from Git.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/image-145.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click it and follow the steps to create a new site for deployment from your GitHub repositories. Your process should be similar to what is shown in the image below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/image-146.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, the last step before having your app deployed is to make sure you have the correct build commands and environment variables in place. To do that, after you create your site for deployment, go to <strong>Build &amp; deploy</strong> settings screen and enter the following (don’t forget to use your repo URL):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/image-147.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Under <strong>Environment</strong> section is where you need to enter the environment variables as defined in your .env file. Here is how it looks mine:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/image-148.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Note: <em>I have erased the values as this is supposed to be private info and you should not share yours as well.</em></p>
<p>That should be enough for you to have your app deployed on Netlify. Keep in mind the <strong>Deploys</strong> default settings are set to ‘auto publishing’, which means that it will trigger a deploy on each commit you do to the <strong>master branch</strong> in your repo. This is the place where you can trigger a deploy manually as well. This is how my <strong>Deploys</strong> screen looks like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/image-149.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, we saw how can we leverage our web development skills to create applications that can run on a desktop. What we built is a demo application, that lacks a lot of a fully-featured-production-ready app features, but when one wants to learn and share, this would do the job. If you would like to deepen your knowledge in this direction, I would recommend you to try to improve it, by implementing features that are more likely to be seen in a real desktop application.</p>
<p>There are plenty of opportunities to explore out there, I hope this tutorial entertained you enough to keep your flame of curiosity burning even more.</p>
<p>? Thanks for reading! ?</p>
<p><strong>Notes:</strong></p>
<ul>
<li>In order to use Nw.js DevTools you need to install the SDK build —  <a target="_blank" href="https://nwjs.io/downloads/">https://nwjs.io/downloads/</a> - version 0.38.2 or higher.</li>
</ul>
<p><strong>Resources:</strong></p>
<ul>
<li><p><a target="_blank" href="https://daveceddia.com/what-is-a-thunk/">Q: What is a ‘thunk’? A: The sound your head makes when you first hear about redux-thunk. Ok sorry, that was awful. But…daveceddia.com</a></p>
</li>
<li><p>[book] Cross-Platform Desktop Applications: Using Node, Electron, and NW.js</p>
</li>
<li><p>[book] Cross-platform Desktop Application Development: Electron, Node, NW.js, and React</p>
</li>
<li><p><a target="_blank" href="https://github.com/reduxjs/redux-thunk">Thunk middleware for Redux</a></p>
</li>
<li><p><a target="_blank" href="https://reactjs.org/docs/hooks-reference.html#useref">https://reactjs.org/docs/hooks-reference.html#useref</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to use Streams, BLoCs, and SQLite in Flutter ]]>
                </title>
                <description>
                    <![CDATA[ By Eric Grandt Recently, I’ve been working with streams and BLoCs in Flutter to retrieve and display data from an SQLite database. Admittedly, it took me a very long time to make sense of them. With that said, I’d like to go over all this in hopes yo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/using-streams-blocs-and-sqlite-in-flutter-2e59e1f7cdce/</link>
                <guid isPermaLink="false">66d45e3f182810487e0ce147</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SQLite ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 17 Apr 2019 19:58:12 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*ihvDZXwv6oGz760kKUgYTQ.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Eric Grandt</p>
<p>Recently, I’ve been working with streams and BLoCs in Flutter to retrieve and display data from an SQLite database. Admittedly, it took me a very long time to make sense of them. With that said, I’d like to go over all this in hopes you’ll walk away feeling confident in using them within your own apps. I’ll be going into as much depth as I possibly can and explaining everything as simply as possible.</p>
<p>In this post, we’ll be making a simple app from start to finish that makes use of streams, BLoCs, and an SQLite database. This app will allow us to create, modify, and delete notes. If you haven’t done so yet, create a new barebones Flutter app using <code>flutter create APPNAME</code>. It'll be a lot easier to understand all this if you start fresh. Then, later on, implement what you learned into your existing apps.</p>
<p>The first order of business is creating a class to handle the creation of our tables and to query the database. To do this properly, we need to add <code>sqflite</code> and <code>path_provider</code> as dependencies in our <code>pubspec.yaml</code> file.</p>


<p>In case it doesn’t run automatically, run <code>flutter packages get</code> to retrieve the packages. Once it finishes, create a <code>data</code> folder and a <code>database.dart</code> file within it. This class will create a singleton so we can access the database from other files, open the database, and run queries on that database. I've included comments to explain some of the code.</p>


<p>Create another folder, <code>models</code>, and add one file to it: <code>note_model.dart</code>. Here's a great tool to easily make models: <a target="_blank" href="https://app.quicktype.io/#l=dart">https://app.quicktype.io/#l=dart</a>.</p>
<p><strong>NOTE:</strong> Keep in mind that models do NOT have to copy the columns in the table. For example, if you have a user id stored in a table as a foreign key, the model probably shouldn’t contain that user id. Instead, the model should use that user id in order to retrieve an actual <code>User</code> object.</p>


<p>With our note model created, we can add the final functions to our database file that’ll handle all note related queries.</p>


<p>Let’s get started with streams and BLoCs now. If this is your first time working with these, it can be quite daunting. I promise you though that streams and BLoCs are exceptionally simple once you get past the learning phase.</p>
<p>The first thing we need is a <code>blocs</code> folder within the <code>data</code> folder. This folder will contain all our BLoCs, as the name suggests. Let's create the files for each BLoC: <code>bloc_provider.dart</code>, <code>notes_bloc.dart</code>, and <code>view_note_bloc.dart</code>. One BLoC per page and one to provide the BLoCs to those pages.</p>
<p>The <code>bloc_provider</code> is in charge of easily providing our pages with the necessary BLoC and then disposing of it when necessary. Every time we want to use a BLoC, we'll be using the <code>bloc_provider</code>.</p>


<p>Whenever we need a BLoC on one of our pages, we’ll utilize the <code>BlocProvider</code> like this:</p>


<p>Let’s create our notes BLoC which will handle retrieving all our notes and adding new notes to the database. Since our BLoCs are page specific, this BLoC will only be used on the notes page. I’ve commented the code to explain what’s going on.</p>


<p>With the notes BLoC created, we have everything we need to create our notes page. This page will display all our notes, and allow us to add new ones. We’ll put the code for our notes page into <code>main.dart</code>. Once again, I've commented on all the necessary pieces of code to explain what's going on.</p>


<p>Now we need a way to view, edit, save, and delete the notes. This is where the view note BLoC and the view note page come into play. We’ll start with <code>view_note_bloc.dart</code>.</p>


<p>Now we can build the actual page to allow us to interact with our notes. The code for this page is going in <code>view_note.dart</code>.</p>


<p><img src="https://cdn-media-1.freecodecamp.org/images/VM6e-BtScNO6RMweffYoZGr8kiqmcnstM2DE" alt="Image" width="200" height="422" loading="lazy">
<em>Final app using streams, BLoCs, and SQLite</em></p>
<p>That’s all it takes to work with streams, BLoCs, and SQLite. Using them, we’ve created a super simple app that allows us to create, view, edit, and delete notes. I hope this walkthrough has made you more confident in working with streams. You’ll now be able to implement them into your own apps with ease. If you have any questions, please leave a comment as I’d love to answer them. Thanks for reading.</p>
<p>View the full code here: <a target="_blank" href="https://github.com/Erigitic/flutter-streams">https://github.com/Erigitic/flutter-streams</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How I architected a single-page React application ]]>
                </title>
                <description>
                    <![CDATA[ By Gooi Ying Chyi With Data Structures, Components and integration with Redux _Background photo by [Unsplash](https://unsplash.com/photos/A-btl_OPYWA?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText" rel="noopener" target="_blank" ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-i-architected-a-single-page-react-application-3ebd90f59087/</link>
                <guid isPermaLink="false">66c34d3af41767c3c96bacba</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Redux ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sat, 13 Apr 2019 15:21:45 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*XLkAyY1s1ON4sMc3zLC2hQ.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Gooi Ying Chyi</p>
<h4 id="heading-with-data-structures-components-and-integration-with-redux">With Data Structures, Components and integration with Redux</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/nND6eYTLXiJIuT1h3LBvVG3Vk5-UAWrU1NL2" alt="Image" width="800" height="533" loading="lazy">
_Background photo by [Unsplash](https://unsplash.com/photos/A-btl_OPYWA?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;Sven Mieke on &lt;a href="https://unsplash.com/search/photos/architect?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=")</em></p>
<p>I recently built a single-page application that interacts with a backend JSON API server. I chose to use React to deepen my understanding of React fundamentals and how each tool can help in building a scalable frontend.</p>
<p>The stack of this application consists of:</p>
<ul>
<li>Frontend with React/Redux</li>
<li>A backend JSON API server with Sinatra, integrated with Postgres for database persistence</li>
<li>An API client that fetches data from <a target="_blank" href="http://www.omdbapi.com/">OMDb API</a>, written in Ruby</li>
</ul>
<p>For this post, we’ll assume that we have the backend completed. So let’s focus on how design decisions are made on the frontend.</p>
<blockquote>
<p>Side note: The decisions presented here are for reference only and may vary depending on the needs of your application. An example OMDb Movie Tracker app is used here for demonstration.</p>
</blockquote>
<h3 id="heading-the-app">The App</h3>
<p>The application consists of a search input form. A user can input a movie title to return a movie result from <a target="_blank" href="http://www.omdbapi.com/">OMDb</a>. The user can also save a movie with a rating and short comment into a favorites list.</p>
<p><strong>To view the final app, <a target="_blank" href="https://omdb-tracker.herokuapp.com/">click here</a>.</strong> To view the source code, click <a target="_blank" href="https://github.com/YingCGooi/omdb-tracker/tree/master/public/js">here</a>.</p>
<p>When a user searches a movie on the homepage, it looks like this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0gKNb-YMTg5WJIH7IsZjxZe1ql7mSfRSXvFm" alt="Image" width="800" height="548" loading="lazy">
<em>The UI contains a search input form and a movie result below it.</em></p>
<p>For the sake of simplicity, we’ll only focus on designing the core features of the application in this article. You can also skip to <a target="_blank" href="https://medium.com/p/d6eaf235f4d"><strong>Part II: Redux</strong></a> of the series.</p>
<h3 id="heading-data-structure">Data Structure</h3>
<p>Defining appropriate data structures should be one of the most important aspects of designing an app. This should come as the first step, as it determines not only how the frontend should render the elements, but also how the API server should return the JSON responses.</p>
<p>For this app, we’ll need two main pieces of information to properly render our UI: <strong>a single movie result</strong> and <strong>a list of favorited movies</strong>.</p>
<h4 id="heading-movie-result-object">Movie result object</h4>
<p>A single movie result will contain information such as the title, year, description, and poster image. With this, we need to define an object that can store these attributes:</p>
<pre><code>{  <span class="hljs-string">"title"</span>: <span class="hljs-string">"Star Wars: Episode IV - A New Hope"</span>,  <span class="hljs-string">"year"</span>: <span class="hljs-string">"1977"</span>,  <span class="hljs-string">"plot"</span>: <span class="hljs-string">"Luke Skywalker joins forces with a Jedi Knight..."</span>,  <span class="hljs-string">"poster"</span>: <span class="hljs-string">"https://m.media-amazon.com/path/to/poster.jpg"</span>,  <span class="hljs-string">"imdbID"</span>: <span class="hljs-string">"tt0076759"</span>}
</code></pre><p>The <code>poster</code> property is simply a URL to the poster image that will be displayed in the results. If there’s no poster available for that movie, it will be “N/A”, which we will display a placeholder. We will also need an <code>imdbID</code> attribute to uniquely identify each movie. This is useful for determining whether or not a movie result already exists in the favorites list. We’ll explore later on how it works.</p>
<h4 id="heading-favorites-list">Favorites list</h4>
<p>The favorites list will contain all of the movies saved as favorites. The list will look something like this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/yePajd0g-58FZyL3VjU4p5FpUIopTxekHRId" alt="Image" width="800" height="449" loading="lazy">
<em>Each movie also includes additional favorite information (rating and comment)</em></p>
<pre><code>[  { <span class="hljs-attr">title</span>: <span class="hljs-string">"Star Wars"</span>, <span class="hljs-attr">year</span>: <span class="hljs-string">"1977"</span>, ..., <span class="hljs-attr">rating</span>: <span class="hljs-number">4</span> },  { <span class="hljs-attr">title</span>: <span class="hljs-string">"Avatar"</span>, <span class="hljs-attr">year</span>: <span class="hljs-string">"2009"</span>, ..., <span class="hljs-attr">rating</span>: <span class="hljs-number">5</span> }]
</code></pre><p>Keep in mind that we’ll need to look up a specific movie from the list, and the time complexity for this approach is <strong>O(N)</strong>. While it works fine for smaller datasets, imagine having to search for a movie in a favorites list that grows indefinitely.</p>
<p>With this in mind, I chose to go with a hash table with keys as <code>imdbID</code> and values as favorited movie objects:</p>
<pre><code>{  <span class="hljs-attr">tt0076759</span>: {    <span class="hljs-attr">title</span>: <span class="hljs-string">"Star Wars: Episode IV - A New Hope"</span>,    <span class="hljs-attr">year</span>: <span class="hljs-string">"1977"</span>,    <span class="hljs-attr">plot</span>: <span class="hljs-string">"..."</span>,    <span class="hljs-attr">poster</span>: <span class="hljs-string">"..."</span>,    <span class="hljs-attr">rating</span>: <span class="hljs-string">"4"</span>,    <span class="hljs-attr">comment</span>: <span class="hljs-string">"May the force be with you!"</span>,  },  <span class="hljs-attr">tt0499549</span>: {    <span class="hljs-attr">title</span>: <span class="hljs-string">"Avatar"</span>,    <span class="hljs-attr">year</span>: <span class="hljs-string">"2009"</span>,    <span class="hljs-attr">plot</span>: <span class="hljs-string">"..."</span>,    <span class="hljs-attr">poster</span>: <span class="hljs-string">"..."</span>,    <span class="hljs-attr">rating</span>: <span class="hljs-string">"5"</span>,    <span class="hljs-attr">comment</span>: <span class="hljs-string">"Favorite movie!"</span>,  }}
</code></pre><p>With this, we can look up a movie in the favorites list in <strong>O(1)</strong> time by its <code>imdbID</code>.</p>
<blockquote>
<p>Note: the runtime complexity is probably not going to matter in most cases since the datasets are usually small on the client-side. We are also going to perform slicing and copying (also O(N) operations) in Redux anyway. But as an engineer, it’s good to be aware of potential optimizations that we can perform.</p>
</blockquote>
<h3 id="heading-components">Components</h3>
<p>Components are at the heart of React. We’ll need to determine which ones that will interact with the Redux store, and which ones that are only for presentation. We can also reuse some of the presentational components too. Our component hierarchy will look something like this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/CQkO-xEK5ZexcrR2ZcxtT4EEssWFfFVfjTHQ" alt="Image" width="800" height="577" loading="lazy"></p>
<h4 id="heading-main-page">Main page</h4>
<p>We designate our <strong>App</strong> component at the top level. When the root path is visited, it needs to render the <strong>SearchContainer</strong>. It also needs to display flash messages to the user and handle the client-side routing.</p>
<p>The <strong>SearchContainer</strong> will retrieve the movie result from our Redux store, providing information as props to <strong>MovieItem</strong> for rendering. It will also dispatch a search action when a user submits a search in <strong>SearchInputForm</strong>. More on Redux later.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/-vfxKYTuzgfogu4M6eL7rL4JjdDimzZeJgJN" alt="Image" width="800" height="545" loading="lazy">
<em>A modal that allows users to add a rating and comment when saving a favorite.</em></p>
<h4 id="heading-add-to-favorites-form">Add To Favorites Form</h4>
<p>When the user clicks on the “Add To Favorites” button, we will display the <strong>AddFavoriteForm</strong>, a <a target="_blank" href="https://reactjs.org/docs/forms.html">controlled component</a>.</p>
<p>We are constantly updating its state whenever a user changes the rating or input text in the comment text area. This is useful for validation upon form submission.</p>
<p>The <strong>RatingForm</strong> is responsible to render the yellow stars when the user clicks on them. It also informs the current rating value to <strong>AddFavoriteForm</strong>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/sI9SYwjKc0LvLer5OQLAsKTnvbA7etM-Of0S" alt="Image" width="740" height="727" loading="lazy">
<em>The FavoritesContainer contains a list of MovieItem components</em></p>
<h4 id="heading-favorites-tab">Favorites Tab</h4>
<p>When a user clicks on the “Favorites” tab, the <strong>App</strong> renders <strong>FavoritesContainer</strong>.</p>
<p>The <strong>FavoritesContainer</strong> is responsible for retrieving the favorites list from the Redux store. It also dispatches actions when a user changes a rating or clicks on the “Remove” button.</p>
<p>Our <strong>MovieItem</strong> and <strong>FavoritesInfo</strong> are simply presentational components that receive props from <strong>FavoritesContainer</strong>.</p>
<p>We’ll reuse the <strong>RatingForm</strong> component here. When a user clicks on a star in the <strong>RatingForm</strong>, the <strong>FavoritesContainer</strong> receives the rating value and dispatches an update rating action to the Redux store.</p>
<h3 id="heading-redux-store">Redux Store</h3>
<p>Our Redux store will include reducers that handle the search and favorites actions. Additionally, we’ll need to include a status reducer to track state changes when a user initiates an action. We’ll explore more on the status reducer later.</p>
<pre><code><span class="hljs-comment">//store.js</span>
</code></pre><pre><code><span class="hljs-keyword">import</span> { createStore, combineReducers, applyMiddleware } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux'</span>;<span class="hljs-keyword">import</span> thunk <span class="hljs-keyword">from</span> <span class="hljs-string">"redux-thunk"</span>;
</code></pre><pre><code><span class="hljs-keyword">import</span> search <span class="hljs-keyword">from</span> <span class="hljs-string">'./reducers/searchReducer'</span>;<span class="hljs-keyword">import</span> favorites <span class="hljs-keyword">from</span> <span class="hljs-string">'./reducers/favoritesReducer'</span>;<span class="hljs-keyword">import</span> status <span class="hljs-keyword">from</span> <span class="hljs-string">'./reducers/statusReducer'</span>;
</code></pre><pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> createStore(  combineReducers({    search,    favorites,    status  }),  {},  applyMiddleware(thunk))
</code></pre><p>We’ll also apply the Redux Thunk middleware right away. We’ll go more into detail on that later. Now, let’s figure out how we manage the state changes when a user submits a search.</p>
<h3 id="heading-search-reducer">Search Reducer</h3>
<p>When a user performs a search action, we want to update the store with a new search result via <strong>searchReducer</strong>. We can then render our components accordingly. The general flow of events looks like this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0yVmnP0XRxj058OjNxAnsYZ2mLIZCXxVL-tZ" alt="Image" width="800" height="222" loading="lazy"></p>
<p>We’ll treat <strong>“Get search result”</strong> as a black box for now. We’ll explore how that works later with Redux Thunk. Now, let’s implement the reducer function.</p>
<pre><code><span class="hljs-comment">//searchReducer.js</span>
</code></pre><pre><code><span class="hljs-keyword">const</span> initialState = {  <span class="hljs-string">"title"</span>: <span class="hljs-string">""</span>,  <span class="hljs-string">"year"</span>: <span class="hljs-string">""</span>,  <span class="hljs-string">"plot"</span>: <span class="hljs-string">""</span>,  <span class="hljs-string">"poster"</span>: <span class="hljs-string">""</span>,  <span class="hljs-string">"imdbID"</span>: <span class="hljs-string">""</span>,}
</code></pre><pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> (state = initialState, action) =&gt; {  <span class="hljs-keyword">if</span> (action.type === <span class="hljs-string">'SEARCH_SUCCESS'</span>) {    state = action.result;  }  <span class="hljs-keyword">return</span> state;}
</code></pre><p>The <strong>initialState</strong> will represent the data structure defined earlier as a single movie result object. In the reducer function, we handle the action where a search is successful. If the action is triggered, we simply reassign the state to the new movie result object.</p>
<pre><code><span class="hljs-comment">//searchActions.jsexport const searchSuccess = (result) =&gt; ({  type: 'SEARCH_SUCCESS', result});</span>
</code></pre><p>We define an action called <strong>searchSuccess</strong> that takes in a single argument, the movie result object, and returns an action object of type “<strong>SEARCH_SUCCESS</strong>”. We will dispatch this action upon a successful search API call.</p>
<h3 id="heading-redux-thunk-search">Redux Thunk: Search</h3>
<p>Let’s explore how the <strong>“Get search result”</strong> from earlier works. First, we need to make a remote API call to our backend API server. When the request receives a successful JSON response, we’ll dispatch the <strong>searchSuccess</strong> action along with the payload to <strong>searchReducer</strong>.</p>
<p>Knowing that we’ll need to dispatch after an asynchronous call completes, we’ll make use of <a target="_blank" href="https://github.com/reduxjs/redux-thunk">Redux Thunk</a>. Thunk comes into play for making multiple dispatches or delaying a dispatch. With Thunk, our updated flow of events looks like this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/yHA6xMauC4xW6a1nEIAdacp5WFVFSdeISmD-" alt="Image" width="800" height="431" loading="lazy"></p>
<p>For this, we define a function that takes in a single argument <code>title</code> and serves as the initial <strong>search</strong> action. This function is responsible for fetching the search result and dispatching a <strong>searchSuccess</strong> action:</p>
<pre><code><span class="hljs-comment">//searchActions.jsimport apiClient from '../apiClient';</span>
</code></pre><pre><code>...
</code></pre><pre><code><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search</span>(<span class="hljs-params">title</span>) </span>{  <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">dispatch</span>) =&gt;</span> {    apiClient.query(title)      .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {        dispatch(searchSuccess(response.data))      });  }}
</code></pre><p>We’ve set up our API client beforehand, and you can read more about <a target="_blank" href="https://medium.com/@gooiyingchyi/how-i-architected-a-single-page-react-application-part-i-data-structure-components-and-apis-24386cc78a6#40eb">how I set up the API client here</a>. The <code>apiClient.query</code> method simply performs an AJAX GET request to our backend server and returns a Promise with the response data.</p>
<p>We can then connect this function as an action dispatch to our <strong>SearchContainer</strong> component:</p>
<pre><code><span class="hljs-comment">//SearchContainer.js</span>
</code></pre><pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;<span class="hljs-keyword">import</span> { connect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>;<span class="hljs-keyword">import</span> { search } <span class="hljs-keyword">from</span> <span class="hljs-string">'../actions/searchActions'</span>;
</code></pre><pre><code>...
</code></pre><pre><code><span class="hljs-keyword">const</span> mapStateToProps = <span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> (  {    <span class="hljs-attr">result</span>: state.search,  });
</code></pre><pre><code><span class="hljs-keyword">const</span> mapDispatchToProps = <span class="hljs-function">(<span class="hljs-params">dispatch</span>) =&gt;</span> (  {    search(title) {      dispatch(search(title))    },  });
</code></pre><pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> connect(mapStateToProps, mapDispatchToProps)(SearchContainer);
</code></pre><p>When a search request succeeds, our <strong>SearchContainer</strong> component will render the movie result:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/wKuIVFaH6OSKpSeLBSDal3InlrYE90kQ2G7n" alt="Image" width="800" height="393" loading="lazy">
<em>Left: the app renders the movie result | Right: a successful search request</em></p>
<h3 id="heading-handling-other-search-statuses">Handling Other Search Statuses</h3>
<p>Now we have our <strong>search</strong> action working properly and connected to our <strong>SearchContainer</strong> component, we’d like to handle other cases other than a successful search.</p>
<h4 id="heading-search-request-pending">Search request pending</h4>
<p>When a user submits a search, we’ll display a loading animation to indicate that the search request is pending:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/21mRK3c6oKbo-jrWRsZJUVKIod0rOiV0aYJY" alt="Image" width="800" height="420" loading="lazy">
<em>The app displays a spinner animation when waiting for the search result</em></p>
<h4 id="heading-search-request-succeeds">Search request succeeds</h4>
<p>If the search fails, we’ll display an appropriate error message to the user. This is useful to provide some context. A search failure could happen in cases where a movie title is not available, or our server is experiencing issues communicating with the OMDb API.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/QaamwSGVP5uJZINbdEe9W4v5j8OpEF3TH2GZ" alt="Image" width="800" height="202" loading="lazy">
<em>When a movie title is not found in OMDb, we display an error message</em></p>
<p>To handle different search statuses, we’ll need a way to store and update the current status along with any error messages.</p>
<h3 id="heading-status-reducer">Status Reducer</h3>
<p>The <strong>statusReducer</strong> is responsible for tracking state changes whenever a user performs an action. The current state of an action can be represented by one of the three “statuses”:</p>
<ul>
<li>Pending (when a user first initiates the action)</li>
<li>Success (when a request returns a successful response)</li>
<li>Error (when a request returns an error response)</li>
</ul>
<p>With these statuses in place, we can render different UIs based on the current status of a given action type. In this case, we’ll focus on tracking the status of the <strong>search</strong> action.</p>
<p>We’ll start by implementing the <strong>statusReducer</strong>. For the initial state, we need to track the current search status and any errors:</p>
<pre><code><span class="hljs-comment">// statusReducer.jsconst initialState = {  search: '',      // status of the current search  searchError: '', // error message when a search fails}</span>
</code></pre><p>Next, we need to define the reducer function. Whenever our <strong>SearchContainer</strong> dispatches a “SEARCH_[STATUS]” action, we will update the store by replacing the <code>search</code> and <code>searchError</code> properties.</p>
<pre><code><span class="hljs-comment">// statusReducer.js</span>
</code></pre><pre><code>...
</code></pre><pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> (state = initialState, action) =&gt; {  <span class="hljs-keyword">const</span> actionHandlers = {    <span class="hljs-string">'SEARCH_REQUEST'</span>: {      <span class="hljs-attr">search</span>: <span class="hljs-string">'PENDING'</span>,      <span class="hljs-attr">searchError</span>: <span class="hljs-string">''</span>,    },    <span class="hljs-string">'SEARCH_SUCCESS'</span>: {      <span class="hljs-attr">search</span>: <span class="hljs-string">'SUCCESS'</span>,       <span class="hljs-attr">searchError</span>: <span class="hljs-string">''</span>,          },    <span class="hljs-string">'SEARCH_FAILURE'</span>: {      <span class="hljs-attr">search</span>: <span class="hljs-string">'ERROR'</span>,      <span class="hljs-attr">searchError</span>: action.error,     },  }  <span class="hljs-keyword">const</span> propsToUpdate = actionHandlers[action.type];  state = <span class="hljs-built_in">Object</span>.assign({}, state, propsToUpdate);  <span class="hljs-keyword">return</span> state;}
</code></pre><p>We use an <code>actionHandlers</code> hash table here since we are only replacing the state’s properties. Furthermore, it improves readability more than using <code>if/else</code> or <code>case</code> statements.</p>
<p>With our <strong>statusReducer</strong> in place, we can render the UI based on different search statuses. We will update our flow of events to this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/moKAD85gibVfj7nAGAWQ0DOHWGnUCROV1Kvs" alt="Image" width="800" height="470" loading="lazy"></p>
<p>We now have additional <strong>searchRequest</strong> and <strong>searchFailure</strong> actions available to dispatch to the store:</p>
<pre><code><span class="hljs-comment">//searchActions.js</span>
</code></pre><pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> searchRequest = <span class="hljs-function">() =&gt;</span> ({  <span class="hljs-attr">type</span>: <span class="hljs-string">'SEARCH_REQUEST'</span>});
</code></pre><pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> searchFailure = <span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> ({  <span class="hljs-attr">type</span>: <span class="hljs-string">'SEARCH_FAILURE'</span>, error});
</code></pre><p>To update our <strong>search</strong> action, we will dispatch <strong>searchRequest</strong> immediately and will dispatch <strong>searchSuccess</strong> or <strong>searchFailure</strong> based on the eventual success or failure of the Promise returned by Axios:</p>
<pre><code><span class="hljs-comment">//searchActions.js</span>
</code></pre><pre><code>...
</code></pre><pre><code><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search</span>(<span class="hljs-params">title</span>) </span>{  <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">dispatch</span>) =&gt;</span> {    dispatch(searchRequest());
</code></pre><pre><code>apiClient.query(title)      .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {        dispatch(searchSuccess(response.data))      })      .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {        dispatch(searchFailure(error.response.data))      });  }}
</code></pre><p>We can now connect the search status state to our <strong>SearchContainer</strong>, passing it as a prop. Whenever our store receives the state changes, our <strong>SearchContainer</strong> renders a loading animation, an error message, or the search result:</p>
<pre><code><span class="hljs-comment">//SearchContainer.js</span>
</code></pre><pre><code>...(imports omitted)
</code></pre><pre><code><span class="hljs-keyword">const</span> SearchContainer = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> (  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">id</span>=<span class="hljs-string">'search-container'</span>&gt;</span>    <span class="hljs-tag">&lt;<span class="hljs-name">SearchInputForm</span>       <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Search movie title...'</span>      <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{</span> (<span class="hljs-attr">title</span>) =&gt;</span> props.search(title) }    /&gt;    {      (props.searchStatus === 'SUCCESS')      ? <span class="hljs-tag">&lt;<span class="hljs-name">MovieItem</span>          <span class="hljs-attr">movie</span>=<span class="hljs-string">{</span> <span class="hljs-attr">props.result</span> }          <span class="hljs-attr">...</span>(<span class="hljs-attr">other</span> <span class="hljs-attr">props</span>)        /&gt;</span>      : null    }    {      (props.searchStatus === 'PENDING')      ? <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'loading'</span>&gt;</span>          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">'../../images/loading.gif'</span> /&gt;</span>        <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>      : null    }    {      (props.searchStatus === 'ERROR')      ? <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'error'</span>&gt;</span>           <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'error'</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"red exclamation triangle icon"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>            { props.searchError }          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>        <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>      : null    }  <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>);
</code></pre><pre><code><span class="hljs-keyword">const</span> mapStateToProps = <span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> (  {    <span class="hljs-attr">searchStatus</span>: state.status.search,    <span class="hljs-attr">searchError</span>: state.status.searchError,    <span class="hljs-attr">result</span>: state.search,  });
</code></pre><pre><code>...
</code></pre><h3 id="heading-favorites-reducer">Favorites Reducer</h3>
<p>We’ll need to handle CRUD actions performed by a user on the favorites list. Recalling from our API endpoints earlier, we’d like to allow users to perform the following actions and update our store accordingly:</p>
<ul>
<li>Save a movie into the favorites list</li>
<li>Retrieve all favorited movies</li>
<li>Update a favorite’s rating</li>
<li>Delete a movie from the favorites list</li>
</ul>
<p>To ensure that the reducer function is pure, we simply copy the old state into a new object together with any new properties using<code>Object.assign</code>. Note that we only handle actions with types of <strong>_SUCCESS</strong>:</p>
<pre><code><span class="hljs-comment">//favoritesReducer.js</span>
</code></pre><pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> (state = {}, action) =&gt; {  <span class="hljs-keyword">switch</span> (action.type) {    <span class="hljs-keyword">case</span> <span class="hljs-string">'SAVE_FAVORITE_SUCCESS'</span>:      state = <span class="hljs-built_in">Object</span>.assign({}, state, action.favorite);      <span class="hljs-keyword">break</span>;
</code></pre><pre><code><span class="hljs-keyword">case</span> <span class="hljs-string">'GET_FAVORITES_SUCCESS'</span>:      state = action.favorites;      <span class="hljs-keyword">break</span>;
</code></pre><pre><code><span class="hljs-keyword">case</span> <span class="hljs-string">'UPDATE_RATING_SUCCESS'</span>:      state = <span class="hljs-built_in">Object</span>.assign({}, state, action.favorite);      <span class="hljs-keyword">break</span>;
</code></pre><pre><code><span class="hljs-keyword">case</span> <span class="hljs-string">'DELETE_FAVORITE_SUCCESS'</span>:      state = <span class="hljs-built_in">Object</span>.assign({}, state);      <span class="hljs-keyword">delete</span> state[action.imdbID];      <span class="hljs-keyword">break</span>;
</code></pre><pre><code><span class="hljs-keyword">default</span>: <span class="hljs-keyword">return</span> state;  }  <span class="hljs-keyword">return</span> state;}
</code></pre><p>We’ll leave the <strong>initialState</strong> as an empty object. The reason is that if our <strong>initialState</strong> contains placeholder movie items, our app will render them immediately before waiting for the actual favorites list response from our backend API server.</p>
<p>From now on, each of the favorites action will follow a general flow of events illustrated below. The pattern is similar to the search action in the previous section, except right now we’ll skip handling any “PENDING” status.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/DEOjBJXFxeZIaQDKMU5Y-4aQbLX98VRy3R4d" alt="Image" width="800" height="385" loading="lazy"></p>
<h4 id="heading-save-favorites-action">Save Favorites Action</h4>
<p>Take the save favorites action for example. The function makes an API call to with our <strong>apiClient</strong> and dispatches either a <strong>saveFavoriteSuccess</strong> or a <strong>saveFavoriteFailure</strong> action, depending on whether or not we receive a successful response:</p>
<pre><code><span class="hljs-comment">//favoritesActions.jsimport apiClient from '../apiClient';</span>
</code></pre><pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> saveFavoriteSuccess = <span class="hljs-function">(<span class="hljs-params">favorite</span>) =&gt;</span> ({  <span class="hljs-attr">type</span>: <span class="hljs-string">'SAVE_FAVORITE_SUCCESS'</span>, favorite});
</code></pre><pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> saveFavoriteFailure = <span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> ({  <span class="hljs-attr">type</span>: <span class="hljs-string">'SAVE_FAVORITE_FAILURE'</span>, error});
</code></pre><pre><code><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">save</span>(<span class="hljs-params">movie</span>) </span>{  <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">dispatch</span>) =&gt;</span> {    apiClient.saveFavorite(movie)      .then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {        dispatch(saveFavoriteSuccess(res.data))      })      .catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> {        dispatch(saveFavoriteFailure(err.response.data))      });  }}
</code></pre><p>We can now connect the <strong>save</strong> favorite action to <strong>AddFavoriteForm</strong> through React Redux.</p>
<p>To read more about how I handled the flow to display flash messages, <a target="_blank" href="https://blog.usejournal.com/how-i-architected-a-single-page-react-application-part-ii-redux-d6eaf235f4d#956b">click here</a>.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Designing the frontend of an application requires some forethought, even when using a popular JavaScript library such as React. By thinking about how the data structures, components, APIs, and state management work as a whole, we can better anticipate edge cases and effectively fix errors when they arise. By using certain design patterns such as controlled components, Redux, and handling AJAX workflow using Thunk, we can streamline managing the flow of providing UI feedback to user actions. Ultimately, how we approach the design will have an impact on usability, clarity, and future scalability.</p>
<h4 id="heading-references">References</h4>
<p><a target="_blank" href="https://www.fullstackreact.com/#table-of-contents">Fullstack React: The Complete Guide to ReactJS and Friends</a></p>
<h3 id="heading-about-me">About me</h3>
<p>I am a software engineer located in NYC and co-creator of <a target="_blank" href="https://spacecraft-repl.com">SpaceCraft</a>. I have experience in designing single-page applications, synchronizing state between multiple clients, and deploying scalable applications with Docker.</p>
<p><strong>I am currently looking for my next full-time opportunity! Please <a target="_blank" href="https://gooi.tech">get in touch</a> if you think that I will be a good fit for your team.</strong></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to build a flip timer in React Native ]]>
                </title>
                <description>
                    <![CDATA[ By Pritish Vaidya Introduction A Flip Timer is a digital time keeping device with the time indicated by numbers that are sequentially revealed by a split-flap display. This article will demonstrate the building of a Flip Timer in React Native using i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-flip-timer-in-react-native-e208e54baf58/</link>
                <guid isPermaLink="false">66c34f6f9972b7c5c7624ea1</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sat, 02 Mar 2019 00:00:00 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/0*273pYX1ym8bIxTou" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Pritish Vaidya</p>
<h3 id="heading-introduction">Introduction</h3>
<p>A <em>Flip Timer</em> is a digital time keeping device with the time indicated by numbers that are sequentially revealed by a split-flap display.</p>
<p>This article will demonstrate the building of a <em>Flip Timer</em> in React Native using its exposed APIs and no additional dependencies.</p>
<h3 id="heading-challenges-to-overcome">Challenges to overcome</h3>
<ul>
<li>Implement <code>transform-origin</code> property using your <strong><em>College Math Course</em></strong> matrices techniques since it is not supported in React Native. Rotation around the centered origin (by default) is easy, but we need to translate origin and rotate around the edges.</li>
<li>Implementation of Flip Number component.</li>
<li>Overcome <code>overflow: hidden</code> issue in android since it doesn’t work with absolute positioned elements.</li>
</ul>
<h3 id="heading-contents">Contents</h3>
<ol>
<li><strong>Implement Flip Number Component</strong></li>
<li><p><strong>Implement FoldView</strong></p>
</li>
<li><p>Basic Layout</p>
</li>
<li>Overcoming the Challenge</li>
<li>Adding the Transformations</li>
<li><p>Adding the Animations</p>
</li>
<li><p><strong>Update Timer Component</strong></p>
</li>
<li><p><strong>Final Result</strong></p>
</li>
<li><p><strong>Links</strong></p>
</li>
</ol>
<h3 id="heading-implement-flip-number-component">Implement Flip Number Component</h3>
<h4 id="heading-basic-layout">Basic Layout</h4>
<p>The Basic Layout consists of two cards — upper and lower joined together so that the view looks like a Flip Timer.</p>
<p><strong>Number Card</strong></p>
<p>It is a basic layout consisting of a wrapper and two cards — <em>lower</em>, <em>upper.</em></p>
<p><strong>Note</strong>: Lower Card has the previous number added to it. Its use will be revealed once we reach the <em>FoldView</em> implementation.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/uzy-CsNuZji7eCwWTu6LYYOhygfzB4uP7v68" alt="Image" width="800" height="862" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/components/flip-number/number-card.js" rel="noopener" target="<em>blank" title=")</em></p>
<p><strong>Card</strong></p>
<p>The wrapper of the card has <code>overflow: hidden</code>, and we’re translating its items (number) based on the type of the card (upper or lower).</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/-1JOq61At7-JFxeyTRsn5vgtzCZYTL9UkZ-M" alt="Image" width="800" height="763" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/components/flip-number/card.js" rel="noopener" target="<em>blank" title=")</em></p>
<h3 id="heading-implement-foldview">Implement FoldView</h3>
<h4 id="heading-basic-layout-1">Basic Layout</h4>
<p>To build FoldView we need two <em>FlipCards</em> similar to <em>NumberCards</em> but with <em>absolute positioning</em> so that they are above the <em>NumberCards</em> when flip animations are applied.</p>
<p><strong>Number Card</strong></p>
<p>Adding <em>FlipCard</em> component to the <em>NumberCard</em> component.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/YrmnGEZBPPoxwsvskGYqHaYzPJ4VkB8viPO1" alt="Image" width="722" height="806" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/components/flip-number/number-card.js" rel="noopener" target="<em>blank" title=")</em></p>
<p><strong>Flip Card</strong></p>
<p>The FlipCard component is an animated wrapper with absolute positioning used while applying flip animation.</p>
<p><strong>Challenge (Part 2 and Part 3)</strong>: <code>overflow: hidden</code> with absolute positioning has major issues in <em>android.</em> Using this <a target="_blank" href="https://stackoverflow.com/a/21684490/6606831">StackOverflow</a> post, it can be solved by using an <em>overflow container</em> inside the absolute positioned element.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/KG-NyI8-vafcBiZGWoZaD1hpCpwW0V-3ff3a" alt="Image" width="800" height="899" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/components/flip-number/flip-card.js" rel="noopener" target="<em>blank" title=")</em></p>
<h4 id="heading-final-result">Final Result</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/qCA0sQ1vuVxxPDWMqOirMoOXtPhRh2-Rwyrl" alt="Image" width="168" height="284" loading="lazy"></p>
<h4 id="heading-overcoming-the-challenge">Overcoming the Challenge</h4>
<p>Now comes the hard part. We need to add fold the FlipCard component along the edges.</p>
<p>Since React Native doesn’t support <code>transform-origin</code> property, we need to find some other way to shift the rotation origin on the bottom edge.</p>
<p>Fortunately, there is one way to overcome this issue. According to this awesome <a target="_blank" href="https://commitocracy.com/implementing-foldview-in-react-native-e970011f98b8">article</a> and reading the <a target="_blank" href="https://developer.mozilla.org/en-US/">MDN</a> docs for the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin">transform-origin</a> property, it can be implemented using <strong>matrices.</strong></p>
<p><strong>Utils</strong></p>
<p>React Native exposes several matrix operations in the <a target="_blank" href="https://github.com/facebook/react-native/blob/master/Libraries/Utilities/MatrixMath.js">MatrixMath.js</a>. The important ones that we require are</p>
<ul>
<li><strong>Identity Matrix:</strong> It returns a 4 * 4 identity matrix <code>[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]</code></li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/J7CO8Ge-QqrmmFwuphxEwbypurpEPgQFUqeQ" alt="Image" width="800" height="283" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/utils/index.js" rel="noopener" target="<em>blank" title=")</em></p>
<ul>
<li><strong>Multiply Matrix:</strong> This utility method generates output based on the multiplication of 4*4 matrices <code>a</code> and <code>b</code> supplied as input.</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1xbhTbClhu47mEsGPa7p4T7wHsajXl3PAy0J" alt="Image" width="800" height="283" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/utils/index.js" rel="noopener" target="<em>blank" title=")</em></p>
<ul>
<li><strong>Rotate Matrix:</strong> It is a custom utility method that will take a 4*4 matrix and degree to which it will be rotated to then multiply it to the original matrix to return the generated result.</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/qa2oiTgiOehlLCu4Qqfcj6zhNofoKpfA-1XL" alt="Image" width="510" height="158" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/q2MBhiltQRvtPmHC8r28UGvBDGPYOSTyEriN" alt="Image" width="800" height="519" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/utils/index.js" rel="noopener" target="<em>blank" title=")</em></p>
<ul>
<li><strong>Perspective Matrix:</strong> This utility method will allow us to use the perspective style to React Native and then multiply to the original 4*4 matrix.</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0HmvXN1gu3-hGoK1ydxmf-8rBmxtIJEe3PNi" alt="Image" width="474" height="206" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/RjIzOwoDY1-1vvH1Y9lu7RC-opK8hpS1vSoL" alt="Image" width="800" height="381" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/utils/index.js" rel="noopener" target="<em>blank" title=")</em></p>
<ul>
<li><strong>Translate Matrix:</strong> This utility method will translate the origin and modify the original 4*4 matrix</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/OwRIvTNQ6f4YHisOmGSU362njvxovBFJ8JVy" alt="Image" width="368" height="214" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ThtIdQR5osqzP5GMmxFGvQB5oUbuUUHMMwRv" alt="Image" width="800" height="345" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/utils/index.js" rel="noopener" target="<em>blank" title=")</em></p>
<ul>
<li><strong>Un-Translate Matrix:</strong> This utility method will un-translate the origin and modify the original 4*4 matrix</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/P0Ct10em0E2zebJeY2UTdZKMW2JmWyM62xMJ" alt="Image" width="673" height="295" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/utils/index.js" rel="noopener" target="<em>blank" title=")</em></p>
<h4 id="heading-adding-the-transformations">Adding the Transformations</h4>
<p><code>deg</code> is the degree to be rotated and <code>y</code> is the height of the component to which it will be translated.</p>
<p><strong>Challenge (Part 1)</strong>: Combining the utils from the above, <code>transform-origin</code> is implemented successfully.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/e9M2yLlahuXIQJ03D3UdvbQSNxSLlY-Lppdk" alt="Image" width="800" height="173" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/2qvRlyie7oBWQUwfyOn1t7RAvnZQ-rALAyj9" alt="Image" width="800" height="409" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/components/timer.js" rel="noopener" target="<em>blank" title=")</em></p>
<h4 id="heading-adding-the-animations">Adding the Animations</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/GBeUP2fLLmHCcbS6gpVdXBR1DwRMuULV2t2t" alt="Image" width="800" height="1328" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/components/timer.js" rel="noopener" target="<em>blank" title=")</em></p>
<h3 id="heading-update-timer-component">Update Timer Component</h3>
<h4 id="heading-add-time-util">Add Time Util</h4>
<p>This util will increment the timer by one sec and adjust hours, minutes, seconds.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/3r0RZrCsJG4d0J3VNbjKaO4lPlySXO1Cxl0S" alt="Image" width="800" height="798" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/utils/index.js" rel="noopener" target="<em>blank" title=")</em></p>
<h4 id="heading-timer-component">Timer Component</h4>
<p>The timer component will call <strong>Time Util</strong> and update the component based on hours, minutes, seconds</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ZcNz-7U5YSbU8UYyQwKijO8cfpEE2-CL1pN4" alt="Image" width="800" height="914" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/components/timer.js" rel="noopener" target="<em>blank" title=")</em></p>
<h4 id="heading-flip-number-component">Flip Number Component</h4>
<p>This component just splits the number into two parts based on their digit placement and calls <strong>NumberCard</strong> component .</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/MPgjFf9b9pYxOTVO461fBB-Dqh-8O25D3z5b" alt="Image" width="800" height="571" loading="lazy">
_Image Credit: [GitHub](https://github.com/dawnlabs/carbon" rel="noopener" target="_blank" title=""&gt;Carbon. | Code: &lt;a href="https://github.com/pritishvaidya/react-native-flip-timer/blob/master/src/components/flip-number/index.js" rel="noopener" target="<em>blank" title=")</em></p>
<h3 id="heading-final-result-1">Final Result</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/c93caflCfnyqBNcQed-BOGQITYP-QFngekZ8" alt="Image" width="600" height="143" loading="lazy"></p>
<h3 id="heading-links">Links</h3>
<p>I’ve published a package for it that contains more customizable properties.</p>
<ul>
<li>npm : <a target="_blank" href="https://www.npmjs.com/package/react-native-flip-timer">react-native-flip-timer</a></li>
<li>GitHub: <a target="_blank" href="https://github.com/pritishvaidya/react-native-flip-timer">react-native-flip-timer</a></li>
</ul>
<p>More of the cool stuff can be found on my <a target="_blank" href="https://stackoverflow.com/users/6606831/pritish-vaidya"><strong><em>StackOverflow</em></strong></a> and <a target="_blank" href="https://github.com/pritishvaidya"><strong><em>GitHub</em></strong></a> profiles.</p>
<p>Follow me on <a target="_blank" href="https://www.linkedin.com/in/pritish-vaidya-506686128/"><strong><em>LinkedIn</em></strong></a>, <a target="_blank" href="https://medium.com/@pritishvaidya94"><strong><em>Medium</em></strong></a>, <a target="_blank" href="https://twitter.com/PritishVaidya"><strong><em>Twitter</em></strong></a> for further update new articles.</p>
<p><strong>One clap, two claps, three claps, forty?</strong></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/6nEX6G3ucbC8JOm8KkdqSWhrwBusRHDmmQkH" alt="Image" width="600" height="244" loading="lazy"></p>
<p><em>Originally published at <a target="_blank" href="https://blog.pritishvaidya.com/posts/2019-03-02-building-a-flip-timer-in-react-native/">blog.pritishvaidya.com</a> on March 2, 2019.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Here’s a breakdown of all the important features of Magento 2.3 ]]>
                </title>
                <description>
                    <![CDATA[ By Santhosh Sundararajan Magento 2.3 is finally here and it has come packed with significant enhancements and amazing features. Some of the features are so great that you might want your upgrade your online store to Magento 2.3 right now! So, what ar... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/heres-a-breakdown-of-all-the-important-features-of-magento-2-3-a83ad3a017bf/</link>
                <guid isPermaLink="false">66c34c5ba7aea9fc97bdfb4a</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ecommerce ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Magento ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 27 Feb 2019 23:31:27 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*6qZ1yAHvfOxQaSoogDV4TA.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Santhosh Sundararajan</p>
<p>Magento 2.3 is finally here and it has come packed with significant enhancements and amazing features. Some of the features are so great that you might want your upgrade your online store to Magento 2.3 right now!</p>
<h4 id="heading-so-what-are-those-features-in-magento-23">So, what are those features in Magento 2.3?</h4>
<p>Magento 2.3 is packed with incredible features such as:</p>
<ul>
<li>PWA that enables businesses to deliver a superior mobile experience,</li>
<li>Multi-Source Inventory for managing inventory from various sources,</li>
<li>Page Builder with drag and drop interface functionality for easier content management, and</li>
<li>Elasticsearch with advanced search options which was available only in Magento Commerce is now available in Magento Open Source.</li>
</ul>
<p>Let’s go through each of these features now.</p>
<h3 id="heading-1-pwas">1. PWAs</h3>
<p>Progressive Web Apps (PWAs) have been the hottest talk in the design and app communities for past few years. In 2017, <a target="_blank" href="https://magento.com/news-room/press-releases/magento-reimagine-mobile-commerce-progressive-web-apps">Magento officially announced</a> that it would collaborate with Google to bring native PWA features to Magento in 2018.</p>
<p>PWAs can deliver a rich experience similar to mobile apps and have features that can improve conversion rates. Customers using PWAs will have <strong>a similar experience to using an actual app</strong>. They also provide a seamless scrolling experience and easy transition between pages. Here’s more about <a target="_blank" href="https://www.codilar.com/blog/magento-pwa/?utm_source=medium&amp;utm_medium=magento-2-3-features">Magento PWAs</a>, and you can also <a target="_blank" href="http://pwa.codilar.in/">check live Magento PWA demo here</a> to see the features yourself.</p>
<h4 id="heading-11-what-are-the-advantages-of-using-pwas">1.1 What are the advantages of using PWAs?</h4>
<p><strong>Incredible speed</strong> — PWAs use various optimization strategies to load the website content faster, thereby improving the customer experience.</p>
<p><strong>Offline support</strong> — Visitors can access and use PWAs either partially or completely in offline mode or when the internet is unstable.</p>
<p><strong>Cross-browser compatibility</strong> — PWAs can function quite well on almost all leading web browsers such as Chrome, Firefox, Safari and Edge.</p>
<p><strong>Responsive design</strong> — Highly responsive design methods are used to deliver a consistent experience on desktops, mobile phones, and tablet devices. Also, PWAs use a mobile-first strategy, and this will help in boosting sales, as a major part of sales take place via mobile phones.</p>
<p><strong>Add to home screen</strong> — Customers can add PWA sites to the home screen of their mobile phones. This will enable them to launch the PWA right from the home screen by directly clicking on it. Hence the customers don’t have to go to the browser and then to the website. This can increase online traffic as well as improve the customer experience.</p>
<p><strong>Push notification</strong> — Businesses can send push notifications to their customers via PWAs. Push notifications are the message popups that appear on mobile devices. For instance, if your business is running a limited offer, sending out a push notification for the same increases the chances of customers’ participation in the offer. This could significantly increase the conversion rate.</p>
<p>If you are a developer, this official <a target="_blank" href="https://magento-research.github.io/pwa-studio/">Magento PWA documentation</a> will be helpful in building a Magento PWA.</p>
<h4 id="heading-12-why-is-magento-using-pwas">1.2 Why is Magento using PWAs?</h4>
<p>Almost <a target="_blank" href="https://www.statista.com/chart/13139/estimated-worldwide-mobile-e-commerce-sales/">63.5% of all the e-commerce sales</a> in 2018 took place via mobile phones, and by 2020 it is expected to reach 70.4%.</p>
<p>Even during Black Friday in 2018, mobile and tablet devices accounted for <a target="_blank" href="https://techcrunch.com/2018/11/23/black-friday-ecommerce/">almost half of the online sales</a>. Hence, it is no wonder that Magento is looking for ways to effectively tap the m-commerce market. PWAs are the next big thing in web development, so Magento has decided to incorporate PWAs in its online stores.</p>
<h3 id="heading-2-multi-source-inventory-msi">2. Multi-Source Inventory (MSI)</h3>
<p>This can be expected to be the most loved feature for business owners and store admins who handle inventory from multiple sources.</p>
<p>With Multi-Source Inventory (MSI), effective and easy management of inventory in <strong>various locations and shipping networks</strong> is possible. Earlier, to use this feature, businesses have to install third-party extensions. MSI includes features such as inventory tracking across various sources, the option to set rules to control operations as planned, and so on.</p>
<h3 id="heading-3-page-builder-only-for-magento-commerce">3. Page Builder (only for Magento Commerce)</h3>
<p>The Page Builder feature is a great addition to the Magento Content Management System (CMS). Handling a site and its content is a difficult job if you have to use HTML and CSS all the time. So Magento has come up with Page Builder.</p>
<p>Content Management Systems are crucial for e-commerce websites since various content formats such as image, text and video are used to give information about the product. The way the content is presented is equally important to what the content says. Also, managing content should be hassle-free and less time-consuming.</p>
<p>WordPress is one of the best CMS systems currently, and it is used by millions of websites. Two main reasons that WordPress is successful are its user-friendly interface and SEO optimized nature. Since WordPress is more like a destination for bloggers and regular websites, it is expected to have these features. Magento has also decided to deliver a similar yet more powerful CMS to store owners by adding Page Builder to its existing CMS.</p>
<p>Page Builder has a <strong>drag and drop interface and a flexible grid system</strong> which helps non-technical business owners easily handle content on their website. Store owners can blend content with commerce and deliver an impactful experience to their customers.</p>
<p>New pages, categories, and products can be created and launched without the need of a front-end developer.</p>
<p>It is currently available in the Early Adopter Program. To participate, contact Magento via <a target="_blank" href="mailto:PageBuilderEAP@adobe.com">PageBuilderEAP@adobe.com</a>.</p>
<h3 id="heading-4-elasticsearch">4. Elasticsearch</h3>
<p>Until now, Elasticsearch was available only to Magento Commerce versions. Starting from 2.3, this feature will be available in Magento Open Source as well.</p>
<p>Elasticsearch provides advanced search capabilities such as <strong>filtering by attributes.</strong> The fuzzy query is also an attribute of Elasticsearch that gives the right suggestions for keywords with incorrect spelling entered by users. It can also provide predictive search results that can save time and effort for customers. Also, it can deliver results quickly, and the database is scalable to a great extent since it uses distributed search.</p>
<p>This can help customers to narrow down what they are looking by just using the filtering options.</p>
<h3 id="heading-what-does-magento-23-mean-for-developers">What does Magento 2.3 mean for developers?</h3>
<p>Magento 2.3 has surprises for developers too. GraphQL which was officially introduced by Facebook has been incorporated in Magento 2.3. Upgradation and installation processes are now easier, thanks to the declarative schema. Support for PHP 7.2 is included in Magento 2.3. Asynchronous APIs and Web APIs are also added</p>
<h4 id="heading-1-graphql">1. GraphQL</h4>
<p><a target="_blank" href="https://devdocs.magento.com/guides/v2.3/graphql/index.html">GraphQL</a> is the main reason that PWAs <strong>function even on a slow network</strong>. It was released by Facebook in 2015, and it is one of the best methods with which to build an API.</p>
<p>This query language makes the PWAs request only the exact data. Since GraphQL requests only small amounts of exact data, it allows PWAs to run even on a weak network.</p>
<p>If this is difficult to understand, let me put in simple words. GraphQL is a syntax that sends requests for fetching data from the server and loading data in the client.</p>
<h4 id="heading-2-declarative-schema">2. Declarative schema</h4>
<p>Upgrade and installation process is made easier in Magento 2.3 with the declarative schema. It uses an XML file to alter the schema which <strong>eliminates the need for numerous database scripts.</strong></p>
<p>Another main advantage of using a declarative schema is the rollback feature. The database changes made on a module can be rolled back to the previous version.</p>
<h4 id="heading-3-php-72">3. PHP 7.2</h4>
<p>It looks like Magento has decided to deliver nothing but the best. Magento has decided to add support for the latest PHP 7.2 version. Since PHP has officially announced that <a target="_blank" href="http://php.net/supported-versions.php">support for PHP 5.6 is ending by 2018</a>, this move by Magento is not a surprise. If your online store is built on any of the Magento 1.x versions, it is likely to be running on PHP 5.6. Failing to <a target="_blank" href="https://www.codilar.com/blog/secure-magento-1-running-on-php-5-6-with-php-7-2/">secure your Magento 1.x website</a> will make it vulnerable to hacks.</p>
<p>PHP 7.2 has plenty of performance and security improvements. Magento websites using PHP 7.2 will be faster, and can handle more requests per second. Also, 7.2 is also more secure and stable.</p>
<h4 id="heading-4-asynchronous-apis-and-bulk-apis">4. Asynchronous APIs and Bulk APIs</h4>
<p><a target="_blank" href="https://devdocs.magento.com/guides/v2.3/rest/asynchronous-web-endpoints.html">Asynchronous APIs</a> can process numerous API requests without the need for the server to respond. In previous versions, Magento used REST API which would wait for sometime to process the response.</p>
<p>This message queue feature that enables asynchronous execution was available only in the Magento Commerce. It has now been extended to Magento Open Source.</p>
<p><a target="_blank" href="https://devdocs.magento.com/guides/v2.3/rest/bulk-endpoints.html">Bulk Web APIs</a> will enable REST APIs to take payloads with multiple entities. These APIs eliminate the conventional method of round-trip overhead.</p>
<h3 id="heading-should-you-upgrade-to-magento-23">Should you upgrade to Magento 2.3?</h3>
<p>Considering the features such as PWAs, MSI and performance upgrades, it is <strong>highly recommended</strong> to switch to Magento 2.3. Especially with PWAs booming in the e-commerce industry, online stores that fail to leverage PWAs will lose their customers to their competitors who utilize PWAs.</p>
<p>Magento 2.3 has more than <strong>30 Magento core security fixes</strong>, two-factor authentication, and Google reCAPTCHA.</p>
<hr>
<p>If you have any suggestions, let me know in the comment section.</p>
<p><em>Originally published at <a target="_blank" href="https://www.codilar.com/blog/magento-2-3-features/">www.codilar.com</a>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to set up & deploy your React app from scratch using Webpack and Babel ]]>
                </title>
                <description>
                    <![CDATA[ So you’ve been using create-react-app a.k.a CRA for a while now. It’s great and you can get straight to coding. But when do you need to eject from create-react-app and start configuring your own React application? There will be a time when we have to... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-set-up-deploy-your-react-app-from-scratch-using-webpack-and-babel-a669891033d4/</link>
                <guid isPermaLink="false">66bd9156abdea6b5b115fefa</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Nathan Sebhastian ]]>
                </dc:creator>
                <pubDate>Thu, 14 Feb 2019 21:41:52 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*NluDivebM4nQi0OLMYuVHw.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>So you’ve been using create-react-app a.k.a CRA for a while now. It’s great and you can get straight to coding. But when do you need to eject from create-react-app and start configuring your own React application? There will be a time when we have to let go of the safety check and start venturing out on our own.</p>
<p>This guide will cover the most simple React configuration that I’ve personally used for almost all of my React projects. By the end of this tutorial we will have our own personal boilerplate and learn some configurations from it.</p>
<h4 id="heading-table-of-contents">Table of Contents</h4>
<ul>
<li>Why create your own configuration?</li>
<li>Configuring webpack 4</li>
<li>Configuring Babel 7</li>
<li>Adding Prettier</li>
<li>Adding source map for better error logs</li>
<li>Setting up ESLint</li>
<li>I found errors! What do I do?</li>
<li>Adding CSS LESS processor</li>
<li>Deploying React app to Netlify</li>
<li>Conclusion</li>
</ul>
<h3 id="heading-why-create-your-own-configuration">Why create your own configuration?</h3>
<p>There are certain reasons that make creating your own React configuration make sense. You are likely good with React and you want to learn how to use tools like webpack and Babel on your own. These build tools are powerful, and if you have some extra time, it’s always good to learn about them.</p>
<p>Developers are naturally curious people, so if you feel you’d like to know how things work and which part does what, then let me help you with it.</p>
<p>Furthermore, hiding React configuration by create-react-app is meant for developers starting to learn React, as <a target="_blank" href="https://youtu.be/G39lKaONAlA?t=873">configuration should not stand in the way of getting started</a>. But when things get serious, of course you need more tools to integrate in your project. Think about:</p>
<ul>
<li>Adding webpack loaders for less, sass</li>
<li>Doing server side rendering</li>
<li>Using new ES versions</li>
<li>Adding MobX and Redux</li>
<li>Making your own configuration just for learning sake</li>
</ul>
<p>If you look around the Internet, there are some hacks to get around CRA limitations like <a target="_blank" href="https://github.com/timarney/react-app-rewired">create-react-app rewired</a>. But really, why not just learn React configuration on your own? I will help you get there. Step by step.</p>
<p>Now that you’re convinced to learn some configuration, let’s start by initializing a React project from scratch.</p>
<p>Open up the command line or Git bash and create a new directory</p>
<pre><code>mkdir react-config-tutorial &amp;&amp; cd react-config-tutorial
</code></pre><p>Initialize NPM project by running:</p>
<pre><code>npm init -y
</code></pre><p>Now install react</p>
<pre><code>npm install react react-dom
</code></pre><p>Also, you can view the <a target="_blank" href="https://github.com/nsebhastian/my-react-boilerplate">source code</a> on GitHub while reading this tutorial for explanations about the settings.</p>
<h3 id="heading-configuring-webpack-4">Configuring webpack 4</h3>
<p>Our first stop will be the webpack. It’s a very popular and powerful tool for configuring not only React, but almost all front-end projects. The core function of webpack is that it takes a bunch of JavaScript files we write in our project and turns them into a single, minified file, so that it will be quick to serve. Starting from webpack 4, we aren’t required to write a configuration file at all to use it, but in this tutorial we will write one so that we can understand it better.</p>
<p>First, let’s do some installation</p>
<pre><code>npm install --save-dev webpack webpack-dev-server webpack-cli
</code></pre><p>This will install:</p>
<ul>
<li><strong>webpack module</strong> — which include all core webpack functionality</li>
<li><strong>webpack-dev-server</strong> — this development server automatically rerun webpack when our file is changed</li>
<li><strong>webpack-cli</strong> — enable running webpack from the command line</li>
</ul>
<p>Let’s try to run webpack by adding the following script to <code>package.json</code></p>
<pre><code class="lang-js"><span class="hljs-string">"scripts"</span>: {
 <span class="hljs-string">"start"</span>: <span class="hljs-string">"webpack-dev-server --mode development"</span>,
},
</code></pre>
<p>Now create an <code>index.html</code> file in your root project with the following content:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
 <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
 <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>My React Configuration Setup<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
 <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
 <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
 <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"root"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
 <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./dist/bundle.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
 <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Create a new directory named <code>src</code> and inside it, create a new <code>index.js</code> file</p>
<pre><code>mkdir src &amp;&amp; cd src &amp;&amp; touch index.js
</code></pre><p>Then write a React component into the file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom"</span>;
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Welcome</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  render() {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hello World from React boilerplate<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
  }
}
ReactDOM.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Welcome</span> /&gt;</span></span>, <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
</code></pre>
<p>Run the webpack by using <code>npm run start</code> … And an error will be triggered.</p>
<pre><code>You may need an appropriate loader to handle <span class="hljs-built_in">this</span> file type
</code></pre><h3 id="heading-configuring-babel-7">Configuring Babel 7</h3>
<p>The React component we wrote above used the <code>class</code> syntax, which is a feature of ES6. Webpack needs Babel to process ES6 into ES5 syntaxes in order for this class to work.</p>
<p>Let’s install Babel into our project</p>
<pre><code>npm install --save-dev @babel/core @babel/preset-env \@babel/preset-react babel-loader
</code></pre><p>Why do we need these packages?</p>
<ul>
<li><strong>@babel/core</strong> is the main dependency that includes babel transform script.</li>
<li><strong>@babel/preset-env</strong> is the default Babel preset used to transform ES6+ into valid ES5 code. Optionally configures browser polyfills automatically.</li>
<li><strong>@babel/preset-react</strong> is used for transforming JSX and React class syntax into valid JavaScript code.</li>
<li><strong>babel-loader</strong> is a webpack loader that hooks Babel into webpack. We will run Babel from webpack with this package.</li>
</ul>
<p>To hook Babel into our webpack, we need to create a webpack configuration file. Let’s write a <code>webpack.config.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">entry</span>: <span class="hljs-string">'./src/index.js'</span>,
  <span class="hljs-attr">output</span>: {
    <span class="hljs-attr">path</span>: __dirname + <span class="hljs-string">'/dist'</span>,
    <span class="hljs-attr">publicPath</span>: <span class="hljs-string">'/'</span>,
    <span class="hljs-attr">filename</span>: <span class="hljs-string">'bundle.js'</span>
  },
  <span class="hljs-attr">devServer</span>: {
    <span class="hljs-attr">contentBase</span>: <span class="hljs-string">'./dist'</span>,
  },
  <span class="hljs-attr">module</span>: {
    <span class="hljs-attr">rules</span>: [
    {
      <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.(js|jsx)$/</span>,
      exclude: <span class="hljs-regexp">/node_modules/</span>,
      use: [<span class="hljs-string">'babel-loader'</span>]
    }
    ]
  },
};
</code></pre>
<p>This webpack config is basically saying that the <code>entry</code> point of our application is from index.js, so pull everything that’s needed by that file, then put the <code>output</code> of the bundling process into the <em>dist</em> directory, named <em>bundle.js</em>. Oh, if we’re running on <code>webpack-dev-server</code>, then tell the server to serve content from <code>contentBase</code> config, which is the same directory this config is in. For all .js or .jsx files, use <code>babel-loader</code> to transpile all of them.</p>
<p>In order to use Babel presets, create a new <code>.babelrc</code> file</p>
<pre><code>touch .babelrc
</code></pre><p>Write the following content:</p>
<pre><code class="lang-js">{
  <span class="hljs-string">"presets"</span>: [
    <span class="hljs-string">"@babel/preset-env"</span>,
    <span class="hljs-string">"@babel/preset-react"</span>
  ]
}
</code></pre>
<p>Now run <code>npm run start</code> again. This time it will work.</p>
<h3 id="heading-adding-prettier">Adding Prettier</h3>
<p>To further speed up development, let’s make our code formatter using Prettier. Install the dependency locally and use the — save-exact argument since Prettier introduces stylistic changes in patch releases.</p>
<pre><code>npm install --save-dev --save-exact prettier
</code></pre><p>Now we need to write the <code>.prettierrc</code> configuration file:</p>
<pre><code class="lang-js">{
 <span class="hljs-string">"semi"</span>: <span class="hljs-literal">true</span>,
 <span class="hljs-string">"singleQuote"</span>: <span class="hljs-literal">true</span>,
 <span class="hljs-string">"trailingComma"</span>: <span class="hljs-string">"es5"</span>
}
</code></pre>
<p>The rules means that we want to add semicolon for the end of every statement, use a single quote whenever appropriate and put trailing commas for multi-line ES5 code like objects or arrays.</p>
<p>You can run Prettier from the command line with:</p>
<pre><code>npx prettier --write <span class="hljs-string">"src/**/*.js"</span>
</code></pre><p>Or add a new script to our <code>package.json</code> file:</p>
<pre><code class="lang-js"><span class="hljs-string">"scripts"</span>: {
 <span class="hljs-string">"test"</span>: <span class="hljs-string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span>,
 <span class="hljs-string">"start"</span>: <span class="hljs-string">"webpack-dev-server --mode development"</span>,
 <span class="hljs-string">"format"</span>: <span class="hljs-string">"prettier --write \"src/**/*.js\""</span>
},
</code></pre>
<p>Now we can run Prettier using <code>npm run format</code>.</p>
<p>Additionally, if you’re using VSCode for development, you can install the <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode">Prettier extension</a> and run it every time you save your changes by adding this setting:</p>
<pre><code><span class="hljs-string">"editor.formatOnSave"</span>: <span class="hljs-literal">true</span>
</code></pre><h3 id="heading-adding-source-map-for-better-error-logs">Adding source map for better error logs</h3>
<p>Since webpack bundles the code, source maps are mandatory to get a reference to the original file that raised an error. For example, if you bundle three source files (<code>a.js</code>, <code>b.js</code>, and <code>c.js</code>) into one bundle (<code>bundler.js</code>) and one of the source files contains an error, the stack trace will simply point to <code>bundle.js</code>. This is problematic as you probably want to know exactly if it’s the a, b, or c file that is causing an error.</p>
<p>You can tell webpack to generate source maps using the devtool property of the configuration:</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">devtool</span>: <span class="hljs-string">'inline-source-map'</span>,
  <span class="hljs-comment">// … the rest of the config</span>
};
</code></pre>
<p>Although it will cause a slower build, it has no effect on production. Sourcemaps are only downloaded <a target="_blank" href="https://stackoverflow.com/a/44316255">if you open the browser DevTools</a>.</p>
<h3 id="heading-setting-up-eslint">Setting up ESLint</h3>
<p>Linter is a program that checks our code for any error or warning that can cause bugs. JavaScript’s linter, ESLint, is a very flexible linting program that can be configured in many ways.</p>
<p>But before we get ahead, let’s install ESLint into our project:</p>
<pre><code>npm --save-dev install eslint eslint-loader babel-eslint eslint-config-react eslint-plugin-react
</code></pre><ul>
<li><strong>eslint</strong> is the core dependency for all functionalities, while eslint-loader enables us to hook eslint into webpack. Now since React used ES6+ syntax, we will add <strong>babel-eslint</strong> — a parser that enables eslint to lint all valid ES6+ codes.</li>
<li><strong>eslint-config-react</strong> and <strong>eslint-plugin-react</strong> are both used to enable ESLint to use pre-made rules.</li>
</ul>
<p>Since we already have webpack, we only have to modify the config slightly:</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-comment">// modify the module</span>
  <span class="hljs-attr">module</span>: {
    <span class="hljs-attr">rules</span>: [{
      <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.(js|jsx)$/</span>,
      exclude: <span class="hljs-regexp">/node_modules/</span>,
      use: [<span class="hljs-string">'babel-loader'</span>, <span class="hljs-string">'eslint-loader'</span>] <span class="hljs-comment">// include eslint-loader</span>
    }]
  },
};
</code></pre>
<p>Then create an eslint config file named <code>.eslintrc</code> with this content:</p>
<pre><code>{
  <span class="hljs-string">"parser"</span>: <span class="hljs-string">"babel-eslint"</span>,
  <span class="hljs-string">"extends"</span>: <span class="hljs-string">"react"</span>,
  <span class="hljs-string">"env"</span>: {
    <span class="hljs-string">"browser"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-string">"node"</span>: <span class="hljs-literal">true</span>
  },
  <span class="hljs-string">"settings"</span>: {
    <span class="hljs-string">"react"</span>: {
      <span class="hljs-string">"version"</span>: <span class="hljs-string">"detect"</span>
    }
  }
}
</code></pre><p>The config is basically saying, <em>“Hey ESLint, please parse the code using <code>babel-eslint</code> before you check it, and when you’re checking it, please check if all the rules from our React rules config is passed. Take global variables from the environment of browser and node. Oh, and if it’s React code, take the version from the module itself. That way the user won’t have to specify the version manually.</em>”</p>
<p>Rather than specifying our own rules manually, we simply extend <code>react</code> rules which were made available by <code>eslint-config-react</code> and <code>eslint-plugin-react</code>.</p>
<h3 id="heading-i-found-errors-what-do-i-do">I found errors! What do I do?</h3>
<p>Unfortunately the only way to really figure out how to fix ESLint errors is by looking at the documentation for <a target="_blank" href="https://eslint.org/docs/rules/">rules</a>. There’s a quick way to fix ESLint errors by using <code>eslint--fix</code>, and it’s actually good for a quick fix. Let’s add a script on our <code>package.json</code> file:</p>
<pre><code class="lang-js"><span class="hljs-string">"scripts"</span>: {
  <span class="hljs-string">"test"</span>: <span class="hljs-string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span>,
  <span class="hljs-string">"start"</span>: <span class="hljs-string">"webpack-dev-server --mode development"</span>,
  <span class="hljs-string">"format"</span>: <span class="hljs-string">"prettier --write \"src/**/*.js\""</span>,
  <span class="hljs-string">"eslint-fix"</span>: “eslint --fix \<span class="hljs-string">"src/**/*.js\""</span>, <span class="hljs-comment">// the eslint script</span>
  <span class="hljs-string">"build"</span>: <span class="hljs-string">"webpack --mode production"</span>
},
</code></pre>
<p>Then run it with <code>npm run eslint-fix</code>. Don’t worry if you’re still fuzzy about ESLint for now. You will learn more about ESLint as you use it.</p>
<h3 id="heading-adding-css-less-processor">Adding CSS LESS processor</h3>
<p>In order to add the LESS processor into our React application, we will require both less and loader packages from webpack:</p>
<pre><code>npm install --save-dev less less-loader css-loader style-loader
</code></pre><p><code>less-loader</code> will compile our less file into css, while <code>css-loader</code> will resolve css syntax like <code>import</code> or <code>url()</code>. The <code>style-loader</code> will get our compiled css and load it up into <code>&lt;sty</code>le&gt; tag in our bundle. This is great for development because it lets us update our style on the fly, without needing to refresh the browser.</p>
<p>Now let’s add some css files to create a new style directory in <code>src/style</code></p>
<pre><code>cd src &amp;&amp; mkdir style &amp;&amp; touch header.less &amp;&amp; touch main.less
</code></pre><p><code>header.less</code> content:</p>
<pre><code class="lang-js">.header {
  background-color: #<span class="hljs-number">3</span>d3d;
}
</code></pre>
<p><code>main.less</code> content:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> <span class="hljs-string">"header.less"</span>;
<span class="hljs-keyword">@color</span>: #f5adad;
<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">background-color</span>: @color;
}
</code></pre>
<p>Now import our <code>main.less</code> file from <code>index.js</code>:</p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-string">"./style/main.less"</span>;
</code></pre><p>Then update our webpack configuration <code>module</code> property:</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>: {
  <span class="hljs-attr">rules</span>: [{
    <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.(js|jsx)$/</span>,
    exclude: <span class="hljs-regexp">/node_modules/</span>,
    use: [<span class="hljs-string">'babel-loader'</span>, <span class="hljs-string">'eslint-loader'</span>]
  },
  {
    <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.less$/</span>,
    use: [
      <span class="hljs-string">'style-loader'</span>,
      <span class="hljs-string">'css-loader'</span>,
      <span class="hljs-string">'less-loader'</span>,
    ],
  },
 ]
},
</code></pre>
<p>Run the start script and we’re good to go!</p>
<h3 id="heading-deploying-react-app-to-netlify">Deploying React app to Netlify</h3>
<p>All applications need to be deployed for the last step, and for React applications, deployment is very easy.</p>
<p>First, let’s change the build output and development <code>contentBase</code> from <code>dist</code> to <code>build</code> in our Webpack config.</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">entry</span>: <span class="hljs-string">'./src/index.js'</span>,
  <span class="hljs-attr">output</span>: {
    <span class="hljs-attr">path</span>: path.resolve(__dirname, <span class="hljs-string">'build'</span>), <span class="hljs-comment">// change this</span>
    <span class="hljs-attr">publicPath</span>: <span class="hljs-string">'/'</span>,
    <span class="hljs-attr">filename</span>: <span class="hljs-string">'bundle.js'</span>
  },
  <span class="hljs-attr">devServer</span>: {
    <span class="hljs-attr">contentBase</span>: <span class="hljs-string">"./build"</span>,
  },
<span class="hljs-comment">//…</span>
</code></pre>
<p>Now let’s install a new Webpack plugin named HtmlWebpackPlugin</p>
<pre><code>npm install html-webpack-plugin -D
</code></pre><p>This plugin will generate <code>index.html</code> file in the same directory where our <code>bundle.js</code> is created by Webpack. In this case, the <code>build</code> directory.</p>
<p>Why do we need this plugin? Because Netlify requires a single directory to be made the root directory, so we can’t use <code>index.html</code> in our root directory using Netlify. You need to update your webpack config to look like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>);
<span class="hljs-keyword">const</span> HtmlWebpackPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'html-webpack-plugin'</span>);
<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">entry</span>: <span class="hljs-comment">//…</span>
  output: {
    <span class="hljs-comment">//…</span>
  },
  <span class="hljs-attr">devServer</span>: {
    <span class="hljs-attr">contentBase</span>: <span class="hljs-string">"./build"</span>,
  },
  <span class="hljs-attr">module</span>: {
    <span class="hljs-comment">//…</span>
  },
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-keyword">new</span> HtmlWebpackPlugin({
      <span class="hljs-attr">template</span>: path.resolve(<span class="hljs-string">'./index.html'</span>),
    }),
  ]
};
</code></pre>
<p>And please remove the <code>script</code> tag from your <code>index.html</code>:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>My React Configuration Setup<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"root"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>My React Configuration Setup<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"root"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Now you can test the config with <code>npm run build</code> command. Once it’s done, push your boilerplate into a GitHub repo. It’s time to deploy our application!</p>
<p>Now let’s register a <a target="_blank" href="https://netlify.com">Netlify</a> account. If you haven’t heard of Netlify before, it’s an amazing static site hosting that provides all the tools you need to deploy a static site for free. What’s a static site? It’s a website created from a collection of static HTML pages, without any backend. Our React boilerplate as it is now counts as a static site, because we have no backend configured and its just HTML and JavaScript.</p>
<p>After sign up, select new site from Git and Choose GitHub as your Git provider:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/WfWqORsZjfHKwOpZ63d-nZUC6N2FF9CPzDrg" alt="Image" width="800" height="365" loading="lazy"></p>
<p>You need to grant permissions for Netlify, and then select your React boilerplate repo.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/MtKFlYYRZVZ7JNcmP8AHiiDV5OLlJoy4hBk5" alt="Image" width="800" height="555" loading="lazy"></p>
<p>Now you need to enter the build command and publishing directory. As you can see, this is why we need <em>HtmlWebpackPlugin</em>, because we need to serve everything from one directory only. Rather than manually updating our root <code>index.html</code> file for changes, we just generate it using the plugin.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/aecd4gyxtTE22EuPoHzXRe1yA9I9BqTaPfa1" alt="Image" width="800" height="771" loading="lazy"></p>
<p>Make sure you have the same command as the screenshot above, or your app might not run.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/T3GN2LRCZtTIfNNOSVPV-tKgrmlllnRVcmcs" alt="Image" width="800" height="506" loading="lazy"></p>
<p>Once the deploys status turns to <code>published</code> (number 2 above), you can go to the random site name Netlify has assigned for your application (number 1).</p>
<p>Your React application is deployed. Awesome!</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>You’ve just created your very own React project boilerplate and deploy it live to Netlify. Congratulations! Granted, I didn’t go very deep on webpack configurations, because this boilerplate is meant to be a generic starter. In some cases where we need advanced features like server side rendering, we need to tweak the configuration again.</p>
<p>But relax! You’ve come this far, which means you already understand what webpack, Babel, Prettier and ESLint do. Webpack has many powerful loaders that can help you with many cases you’ll frequently counter when building a web application.</p>
<p>If you enjoyed this article and want to take your JavaScript skills to the next level, I recommend you check out my new book <em>Beginning Modern JavaScript</em> <a target="_blank" href="https://www.amazon.com/dp/B0CQXHMF8G">here</a>.</p>
<p><a target="_blank" href="https://www.amazon.com/dp/B0CQXHMF8G"><img src="https://www.freecodecamp.org/news/content/images/2024/01/beginning-js-cover.png" alt="beginning-js-cover" width="600" height="400" loading="lazy"></a></p>
<p>The book is designed to be easy to understand and accessible to anyone looking to learn JavaScript. It provides a step-by-step gentle guide that will help you understand how to use JavaScript to create a dynamic application.</p>
<p>Here's my promise: <em>You will actually feel like you understand what you're doing with JavaScript.</em></p>
<p>Until next time!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Why Progressive Decentralization is blockchain’s best hope ]]>
                </title>
                <description>
                    <![CDATA[ By Arthur Camara Immutability is blockchain’s greatest strength and biggest barrier. Progressive decentralization could be the answer. When we released CryptoKitties a year ago, we opted not to fund it up front with an ICO but instead build it on a ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/why-progressive-decentralization-is-blockchains-best-hope-31a497f2673b/</link>
                <guid isPermaLink="false">66c3670321ae2d74bb700a02</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Blockchain ]]>
                    </category>
                
                    <category>
                        <![CDATA[ decentralization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Ethereum ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 06 Feb 2019 19:36:48 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*qgm9rHxUeF-oy6NxHnXv_A.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Arthur Camara</p>
<h4 id="heading-immutability-is-blockchains-greatest-strength-and-biggest-barrier-progressive-decentralization-could-be-the-answer">Immutability is blockchain’s greatest strength and biggest barrier. Progressive decentralization could be the answer.</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/4RiJaG98m8kPcAYjnVLTCKifqTzhXEys5TD-" alt="Image" width="600" height="400" loading="lazy"></p>
<p>When we released <a target="_blank" href="https://www.cryptokitties.co">CryptoKitties</a> a year ago, we opted not to fund it up front with an ICO but instead build it on a sustainable revenue model. That model is this: we collect a fee of 3.75% from every transaction in the game. Given that we’d be unable to change the fee once we launched — CryptoKitties is built on the Ethereum blockchain — people often ask how we arrived at that number.</p>
<p>It sounds like a smart, well-reasoned choice. I could spin a compelling story about how we ran simulations with advanced prediction models to find the fee that would yield optimal returns.</p>
<p>But that’s not true.</p>
<p>The truth is we made an educated guess. We picked a number that felt fair and we committed to it.</p>
<h3 id="heading-immutability-is-awesome-and-scary">Immutability is awesome and scary</h3>
<p>We easily could have chosen wrong, and since you can’t change something once you add it to the blockchain, that would have been <em>cat-astrophic</em>. Fortunately for CryptoKitties, our community is so passionate and the Kitties are so adorable that 3.75% worked just fine.</p>
<p>Immutability, the inability to be edited, is at once the blockchain’s greatest strength and its largest barrier to meaningful adoption. The pressures of immortal code paralyze developers: you can tinker in a test environment forever, but there will always be real-world variables you can’t anticipate. Covering your eyes and hitting launch is no way to make breakthroughs. It’s more likely to produce breakdowns.</p>
<p>Our fee was just one decision among many: how long should breeding a Kitty take? At what rate should their breeding cooldowns slow? How much should a Gen 0 cat cost? On blockchain, even a seemingly minor choice can pose serious, even critical, consequences.</p>
<p>Decentralization offers everyday people immense benefits: the fairness of permanent and universal rules and the transparency of code and behavior which, combined, create security. However, because it’s often implemented with all-or-nothing immutability, blockchain makes agile development impossible and slows teams to a crawl.</p>
<p>Agility requires iteration. Iterating quickly is key to building the best products, and the best products spark mass adoption.</p>
<h3 id="heading-enter-progressive-decentralization">Enter Progressive Decentralization</h3>
<p>We encountered these barriers ourselves building CryptoKitties, which forced us to negotiate including decentralized features while building something that, ya know, works. Since then, we’ve started exploring progressive decentralization in development, an idea we briefly introduced <a target="_blank" href="https://medium.com/dapperlabs/how-we-launched-cryptokitties-latest-feature-6318ecceba9f">a while ago</a>.</p>
<p>Let’s take a deeper dive now.</p>
<p>Simply put, progressive decentralization advocates easing into decentralization in stages rather than diving in headfirst. What that looks like is building mechanisms into smart contracts that confer special powers to the creators up front, then incrementally lock those powers away in a transparent and systematic way.</p>
<p>The critical condition is that the locking mechanisms must be public and immutable from the start. The creator can’t decide to tweak the terms later and indefinitely extend their power. That balance is vital: done correctly, progressive decentralization allows creators the flexibility to repair their code without compromising the decentralized features of the contract.</p>
<h3 id="heading-progressive-decentralization-can-take-many-forms">Progressive decentralization can take many forms</h3>
<p>There’s no one right way to implement progressive decentralization. There are dozens of variables to consider, and the best approach will vary from project to project.</p>
<p>Here are a couple ways developers could approach progressive decentralization:</p>
<ol>
<li>Author multiple contracts with appropriate separation of concerns and the ability to replace some of those contracts. Some decentralized apps (“dapps”) like <a target="_blank" href="https://decentraland.org/">Decentraland</a>, which features upgradable contracts, are already using this.</li>
<li>Configurable variables and permissions to change those values independently. <a target="_blank" href="https://www.etheremon.com/">Etheremon</a>, for instance, <a target="_blank" href="https://github.com/Etheremon/smartcontract/blob/master/EtheremonERC721.sol#L125">grants special permissions</a> to groups of users who become moderators.</li>
<li>Incorporate a predefined set of ascending levels in the contract, each allowing the creators certain capabilities. The levels can only be increased, never decreased, so backtracking isn’t an option. On level 1, for example, the contract owners can play around with all gameplay variables. At level 2, their capability to modify core variables ends. At the final level, the contract revokes all their special privileges.</li>
</ol>
<p>To die-hard decentralists, some of this probably sounds too centralized. But this is just the starting point. There are further measures to balance decentralization with iteration. The solution combines transparency of the purpose and the conditions and constraints in the contracts. These constraints could include:</p>
<ol>
<li><strong>Selection:</strong> Not everything can be modified, only the specific items that we need to iterate.</li>
<li><strong>Range:</strong> For many of the questions around game economies, we may have a general idea but not know the precise answer. Limiting configuration to a certain range guarantees users that the iteration will land within a reasonable scope.</li>
<li><strong>Direction:</strong> Similar to the “levels” concept above, allow certain variables to move only in one direction, decreasing or increasing but never backtracking.</li>
</ol>
<h3 id="heading-holding-creators-accountable">Holding creators accountable</h3>
<p>All this sounds great in theory. But how do we ensure creators stay true to their roadmap and reach the fully decentralized version of their contracts? How can users opt-in early with the guarantee that the system is an application of progressive decentralization? How can we know we won’t end up with just another flawed, centralized system?</p>
<p>Progressive decentralization includes tenets to keep creators accountable:</p>
<h4 id="heading-time-or-block-based-maturity"><strong><em>Time- or block-based maturity</em></strong></h4>
<p>Lock certain configuration values, revoke the owner’s capabilities or move to the next level of maturity past a certain time or block number. Once that point is reached, the contract automatically changes.</p>
<p>Imagine, for example, that CryptoKitties had a runway of 360,000 blocks (around 60 days’ time) from the moment it launched to adjust the Kitties’ breeding <em>cooldown</em> variables. We could tweak the cooldown mechanics until that point, giving ourselves the breathing room to perfect the balance, while still guaranteeing players that we wouldn’t have that power indefinitely.</p>
<h4 id="heading-usage-based-maturity"><strong><em>Usage-based maturity</em></strong></h4>
<p>Lock those capabilities once a certain number of users or transactions are completed. This option needs to be carefully thought out to avoid exploits, but we could have, for example, built configurable fees into CryptoKitties that would lock in after 10,000 transactions.</p>
<h4 id="heading-economic-incentive"><strong><em>Economic incentive</em></strong></h4>
<p>Align the creator’s incentives with increased decentralization. In this scenario, the creators profit more when the contract becomes more decentralized. Perhaps the fee rises with each level the developer ascends, locking in at the maximum fee when they reach full decentralization. Or, alternatively, perhaps they make no money at all until full decentralization is in place. This financial reward motivates the developer to reach decentralization at a reasonable pace.</p>
<h3 id="heading-theres-no-best-approach-to-building-on-the-blockchain">There’s no best approach to building on the blockchain</h3>
<p>“Progressive decentralization” is really an umbrella encompassing many strategies, mechanisms, and tools to make building on the blockchain more viable. The best way to apply progressive decentralization will always depend on the project and use a mix of the concepts outlined above.</p>
<p>Progressive decentralization is not perfect. The ideal smart contract is simple and straightforward, and these measures add complexity. How and how much to incorporate it is a trade-off that needs to be evaluated on a case-by-case basis.</p>
<p>Although it may anger hardline decentralists, we believe progressive decentralization is far better for users in the long run: by giving developers the flexibility to adjust, the consumer gets a more useful product. That means they’ll actually use it, and once it brings value to their lives, they’ll sing its praises to the people around them. That’s how mass adoption starts.</p>
<p>_Authors: <a target="_blank" href="https://medium.com/@arthur_camara">Arthur Camara</a>, <a target="_blank" href="https://medium.com/@dete73">Dieter Shirley</a>, and Grady Mitchell_</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
