<?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[ app development - 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[ app development - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 19 May 2026 04:43:32 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/app-development/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Svelte i18n and Localization Made Easy ]]>
                </title>
                <description>
                    <![CDATA[ Apps are accessible worldwide. This means anyone from anywhere in the world can download your app.  So, if you want to cater to people everywhere, your app needs to support multiple languages.  Fortunately, Svelte is easy to work with, and it makes l... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/svelte-i18n-and-localization-made-easy/</link>
                <guid isPermaLink="false">6752020830d899211b5bda58</guid>
                
                    <category>
                        <![CDATA[ localization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Svelte ]]>
                    </category>
                
                    <category>
                        <![CDATA[ i18n ]]>
                    </category>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ App Localization ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Alex Tray ]]>
                </dc:creator>
                <pubDate>Thu, 05 Dec 2024 19:42:00 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733421094910/f2f91ab6-0717-4135-9f08-719f041471f6.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Apps are accessible worldwide. This means anyone from anywhere in the world can download your app. </p>
<p>So, if you want to cater to people everywhere, your app needs to support multiple languages. </p>
<p>Fortunately, Svelte is easy to work with, and it makes localization (l10n) and internationalization (i18n) quite straightforward. </p>
<p>But it lacks built-in i18n support—so you need to use a library like svelte-i18n or one of the others available. Let’s create a simple Svelte app to demonstrate how localization can be implemented. </p>
<p>We’ll create a welcome screen that can be used in both English and Spanish and then build some more advanced features.</p>
<dl>
<summary>Table of Contents</summary>
<ul>
<li>
  <a href="heading-what-makes-svelte-unique">What Makes Svelte Unique?</a></li>
  <li><a href="heading-how-to-localize-a-svelte-application">How to Localize a Svelte Application?</a></li>
  <li><a href="heading-adding-language-support">Adding Language Support</a></li>
  <li><a href="heading-updating-components-to-use-translations">Updating Components to Use Translations</a></li>
  <li><a href="heading-creating-a-language-switcher">Creating a Language Switcher</a></li>
  <li><a href="heading-adding-advanced-features">Adding Advanced Features</a></li>
<details>
  <li><a href="heading-formatting-numbers-and-currencies">Formatting Numbers and Currencies</a></li>
  <li><a href="heading-formatting-dates">Formatting Dates</a></li>
  <li><a href="heading-localizing-images">Localizing Images</a></li>
<details>
  <li><a href="heading-dynamic-image-paths">Dynamic Image Paths</a></li><li>
  </li><li><a href="heading-integrating-alternative-text-localization">Integrating Alternative Text Localization</a></li>
 <li><a href="heading-switching-svg-content-dynamically">Switching SVG Content Dynamically</a></li>
</details>
  <li><a href="heading-handling-multiple-forms-of-pluralization">Handling Multiple Forms of Pluralization</a></li>
  <li><a href="heading-handling-missing-translations">Handling Missing Translations</a></li>
</details>
  <li><a href="heading-making-your-app-production-ready">Making Your App Production-Ready</a></li>
 <li><a href="heading-best-practices-for-scaling-your-localization">Best Practices for Scaling Your Localization</a></li>
  <li><a href="heading-wrapping-up">Wrapping Up</a></li>
</ul>
</dl>

<h2 id="heading-what-makes-svelte-unique">What Makes Svelte Unique?</h2>
<p>Similar to <a target="_blank" href="https://centus.com/blog/vue-i18n">Vue i18n</a>, Svelte converts code to vanilla JS during the build process. This means your app ships with minimal code and offers excellent performance.</p>
<p>While other frameworks like React and Vue have longer startup times, Svelte’s compilation process changes that. It creates much smaller bundles, and apps run faster by default.</p>
<p>Svelte’s reactive syntax and lightweight nature make it an excellent choice for developers who want efficient, modern applications. </p>
<p>Its minimalism aligns well with the simplicity required in <a target="_blank" href="https://v2cloud.com/blog/best-programming-languages-for-cloud-computing"><strong>cloud development languages</strong></a>, ensuring that applications are lean, scalable, and optimized for cloud environments. </p>
<p>This minimalism also means you may not always have all the required built-in features. But pretty much all the limitations are resolved with the help of external libraries. </p>
<h2 id="heading-how-to-localize-a-svelte-application">How to Localize a Svelte Application</h2>
<p>Let’s jump right into creating a Svelte project now. I’ll create the project using the <code>npm create</code> command. Run the below commands one by one:</p>
<pre><code class="lang-javascript">npm create svelte@latest freecodecamp-localization-demo
cd freecodecamp-localization-demo
npm install
npm install svelte-i18n
</code></pre>
<p>The <code>npm create</code> command will prompt you with a few choices. Here’s what I’ve picked (but you can always adjust this based on your project requirements):</p>
<ul>
<li><p>Skeleton project: Select <strong>Yes</strong>.</p>
</li>
<li><p>Add TypeScript support: Select <strong>No</strong> (or Yes if you prefer TypeScript).</p>
</li>
<li><p>Add ESLint for code linting: Select <strong>Yes</strong>.</p>
</li>
<li><p>Add Prettier for code formatting: Select <strong>Yes</strong>.</p>
</li>
</ul>
<p>Now that we have our project set up, let's create a welcome component that we'll later enhance with translations. </p>
<p>Create a new file called Welcome.svelte in your src directory:</p>
<pre><code class="lang-javascript">&lt;!-- src/Welcome.svelte --&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">export</span> <span class="hljs-keyword">let</span> username;
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Welcome {username}!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</code></pre>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfcaW7fLzjbLa5ysYYu5FplhoGeVNmml9An_l0fcbEwQSxvg5mDbh3PY9b7etS6DESM7ZGdO_R5dqcYaDdgMaaQE2d7w1Q8eU4uAtIfKjHfm58buFwM-KLtJ_bv-x3XyqoYIOgfdQ?key=uXnvRGfJpBUiBb7CkgThtLro" alt="AD_4nXfcaW7fLzjbLa5ysYYu5FplhoGeVNmml9An_l0fcbEwQSxvg5mDbh3PY9b7etS6DESM7ZGdO_R5dqcYaDdgMaaQE2d7w1Q8eU4uAtIfKjHfm58buFwM-KLtJ_bv-x3XyqoYIOgfdQ?key=uXnvRGfJpBUiBb7CkgThtLro" width="1416" height="578" loading="lazy"></p>
<p>This component takes the username property (that I’ve passed from the App.svelte file) and displays a welcome message. </p>
<p>Simple enough for now, but what if your users speak different languages? Let’s add language support.</p>
<h2 id="heading-adding-language-support">Adding Language Support</h2>
<p>To do this, we need to create translation files for each language. Start by creating a new directory called <strong>locales</strong> in your <strong>src</strong> folder. Inside the <strong>locales</strong> folder, create two JSON files—<em>en.json</em> for English and <em>es.json</em> for Spanish.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// src/locales/en.json</span>
{
  <span class="hljs-string">"hello"</span>: <span class="hljs-string">"Hello {username}!"</span>,
  <span class="hljs-string">"buttons"</span>: {
    <span class="hljs-string">"save"</span>: <span class="hljs-string">"Save"</span>,
    <span class="hljs-string">"cancel"</span>: <span class="hljs-string">"Cancel"</span>
  }
}

<span class="hljs-comment">// src/locales/es.json  </span>
{
  <span class="hljs-string">"hello"</span>: <span class="hljs-string">"¡Hola {username}!"</span>,
  <span class="hljs-string">"buttons"</span>: {
    <span class="hljs-string">"save"</span>: <span class="hljs-string">"Guardar"</span>,
    <span class="hljs-string">"cancel"</span>: <span class="hljs-string">"Cancelar"</span>
  }
}
</code></pre>
<p>These files contain our translation strings.</p>
<p>Notice how we've organized them in a nested structure—this helps manage translations as your app grows. </p>
<p>The {username} and {count} placeholders will be replaced with actual values during runtime when we dynamically (or statically) pass the required values.</p>
<p>Next, we need to tell Svelte how to use these translations. For this, we need an <strong>i18n configuration</strong> file:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// src/i18n.js</span>
<span class="hljs-keyword">import</span> { register, init } <span class="hljs-keyword">from</span> <span class="hljs-string">'svelte-i18n'</span>;

register(<span class="hljs-string">'en'</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./locales/en.json'</span>));
register(<span class="hljs-string">'es'</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./locales/es.json'</span>));

init({
  <span class="hljs-attr">fallbackLocale</span>: <span class="hljs-string">'en'</span>,
  <span class="hljs-attr">initialLocale</span>: <span class="hljs-string">'en'</span>,
});
</code></pre>
<p>We’ve registered our translation files and set English as both the initial language and fallback language. The fallback language is used when a translation is missing in the selected language.</p>
<h2 id="heading-updating-components-to-use-translations">Updating Components to Use Translations</h2>
<p>Now we can update our welcome component to use the text from the JSON file:</p>
<pre><code class="lang-javascript">&lt;!-- src/Welcome.svelte --&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">import</span> {  } <span class="hljs-keyword">from</span> <span class="hljs-string">'svelte-i18n'</span>;
  <span class="hljs-keyword">export</span> <span class="hljs-keyword">let</span> username;
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{$('hello', { username })}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</code></pre>
<p>The <code>$_</code> function is a special helper from svelte-i18n that retrieves translated strings. </p>
<p>When we pass { username } as the second argument, it replaces the placeholder in our translation strings with the actual username.</p>
<h2 id="heading-creating-a-language-switcher">Creating a Language Switcher</h2>
<p>How would someone change the language, though? Let's create a simple language selector component:</p>
<pre><code class="lang-javascript">&lt;!-- src/LanguageSelect.svelte --&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">import</span> { locale } <span class="hljs-keyword">from</span> <span class="hljs-string">'svelte-i18n'</span>;

  <span class="hljs-keyword">const</span> languages = [
    { <span class="hljs-attr">code</span>: <span class="hljs-string">'en'</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'English'</span> },
    { <span class="hljs-attr">code</span>: <span class="hljs-string">'es'</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'Español'</span> }
  ];
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
  {#each languages as { code, name }}
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">on:click</span>=<span class="hljs-string">{()</span> =&gt;</span> locale.set(code)}&gt;{name}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  {/each}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</code></pre>
<p>The <strong>bind:value</strong> directive automatically updates the active language when users make a selection. </p>
<p>The locale store from svelte-i18n handles all the behind-the-scenes work of switching languages.</p>
<p>Now let's bring everything together in our main <strong>App</strong> component:</p>
<pre><code class="lang-javascript">&lt;!-- src/App.svelte --&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">import</span> { waitLocale } <span class="hljs-keyword">from</span> <span class="hljs-string">'svelte-i18n'</span>;
  <span class="hljs-keyword">import</span> Welcome <span class="hljs-keyword">from</span> <span class="hljs-string">'./Welcome.svelte'</span>;
  <span class="hljs-keyword">import</span> LanguageSelect <span class="hljs-keyword">from</span> <span class="hljs-string">'./LanguageSelect.svelte'</span>;

  <span class="hljs-keyword">const</span>  username = <span class="hljs-string">'developer'</span>;
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>

{#<span class="hljs-keyword">await</span> waitLocale()}
  &lt;p&gt;Loading...&lt;/p&gt;
{:then}
  &lt;main&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">LanguageSelect</span> /&gt;</span></span>
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Welcome</span> {<span class="hljs-attr">username</span>} /&gt;</span></span>
  &lt;/main&gt;
{/<span class="hljs-keyword">await</span>}
</code></pre>
<p>The <code>waitLocale</code> function ensures translations are loaded before showing content. This prevents flickering or missing translations when the app first loads.</p>
<h2 id="heading-adding-advanced-features">Adding Advanced Features</h2>
<p>As your app grows, you'll need to handle more complex scenarios. Let's look at some common requirements.</p>
<h3 id="heading-formatting-numbers-and-currencies">Formatting Numbers and Currencies</h3>
<p>Different countries handle numbers and currencies quite differently. So for instance, if you show the figure of a hundred thousand to someone from France, and someone from the USA, you’ll need to show the same figure differently. </p>
<p>France → 100 000,00 $</p>
<p>USA → $100,000.00</p>
<p>You see how the thousands are separated by a space and the decimal by a comma in France? Using the US number format will make it quite confusing for someone from France. Here are a few other examples.</p>
<ul>
<li><p>US uses periods for decimals (1,234.56)</p>
</li>
<li><p>Many European countries use commas for decimals and periods for thousands (1.234,56)</p>
</li>
<li><p>Some countries group digits differently (like 1,23,456 in India)</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-comment">// src/lib/formatUtils.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">formatCurrency</span>(<span class="hljs-params">amount, locale, currency = <span class="hljs-string">'USD'</span></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Intl</span>.NumberFormat(locale, {
    <span class="hljs-attr">style</span>: <span class="hljs-string">'currency'</span>,
    currency
  }).format(amount);
}
</code></pre>
<p>You can now use these formatters in your components:</p>
<pre><code class="lang-javascript">&lt;!-- src/lib/PriceDisplay.svelte --&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">import</span> { formatCurrency } <span class="hljs-keyword">from</span> <span class="hljs-string">'./lib/formatUtils'</span>;
  <span class="hljs-keyword">let</span> price = <span class="hljs-number">1234.56</span>;
  <span class="hljs-keyword">let</span> locale = <span class="hljs-string">'en'</span>;
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Price: {formatCurrency(price, locale, 'USD')}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</code></pre>
<p>With this setup, the app now adapts the currency formats to the different locales based on what outputs you ask from it:</p>
<ul>
<li><p>US: "$1,234.56", "1.2M", "15%"</p>
</li>
<li><p>German: "1.234,56 €", "1,2 Mio.", "15 %"</p>
</li>
</ul>
<h3 id="heading-formatting-dates">Formatting Dates</h3>
<p>Similar to currency and number formats, date are formatted differently across different locales. </p>
<p>So, while the US uses MM/DD/YYYY, many European countries use DD/MM/YYYY, and Japan often uses YYYY年MM月DD日. </p>
<p>Luckily, we don’t need to handle this manually. Similar to currency formatting, we have the <code>Intl.DateTimeFormat</code> function that accepts the locale and date in numeric format and returns the appropriately formatted date. </p>
<pre><code class="lang-javascript"><span class="hljs-comment">// src/lib/dateUtils.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">formatDate</span>(<span class="hljs-params">date, locale</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Intl</span>.DateTimeFormat(locale, {
    <span class="hljs-attr">year</span>: <span class="hljs-string">'numeric'</span>,
    <span class="hljs-attr">month</span>: <span class="hljs-string">'long'</span>,
    <span class="hljs-attr">day</span>: <span class="hljs-string">'numeric'</span>
  }).format(date);
}
</code></pre>
<p>You can now use this function in your Svelte app to display the dates correctly for each locale:</p>
<pre><code class="lang-javascript">&lt;!-- src/lib/DateDisplay.svelte --&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">import</span> { formatDate } <span class="hljs-keyword">from</span> <span class="hljs-string">'./lib/dateUtils'</span>;
  <span class="hljs-keyword">let</span> locale = <span class="hljs-string">'en'</span>;
  <span class="hljs-keyword">let</span> today = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Today's date: {formatDate(today, locale)}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</code></pre>
<p>Once implemented, you’ll see the dates get formatted automatically, like below:</p>
<ul>
<li><p>English (US): "September 23, 2024"</p>
</li>
<li><p>Spanish: "23 de septiembre de 2024"</p>
</li>
<li><p>German: "23. September 2024"</p>
</li>
<li><p>Japanese: "2024年9月23日"</p>
</li>
</ul>
<h3 id="heading-localizing-images">Localizing Images</h3>
<p>Don’t forget that localization isn’t just about translating text—your images need attention, too. Culturally relevant visuals, region-specific content like maps or symbols, and adaptable image formats can make all the difference.</p>
<h4 id="heading-dynamic-image-paths"><strong>Dynamic Image Paths</strong></h4>
<p>Use Svelte's reactivity to dynamically load images based on the current locale. For example, you can store localized image paths in a JSON file or directly in your i18n configuration:</p>
<pre><code class="lang-javascript">{
  <span class="hljs-string">"en"</span>: { <span class="hljs-string">"logo"</span>: <span class="hljs-string">"/images/en/logo.png"</span> },
  <span class="hljs-string">"fr"</span>: { <span class="hljs-string">"logo"</span>: <span class="hljs-string">"/images/fr/logo.png"</span> }
}
</code></pre>
<p>Then, in your Svelte component:</p>
<pre><code class="lang-javascript">&lt;script&gt;
  <span class="hljs-keyword">import</span> { locale } <span class="hljs-keyword">from</span> <span class="hljs-string">'svelte-i18n'</span>;
  <span class="hljs-keyword">import</span> translations <span class="hljs-keyword">from</span> <span class="hljs-string">'./translations.json'</span>;

  $: imagePath = translations[$locale].logo;
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{imagePath}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Localized logo"</span> /&gt;</span></span>
</code></pre>
<h4 id="heading-integrating-alternative-text-localization"><strong>Integrating Alternative Text Localization</strong></h4>
<p>Ensure your images' alt attributes are also localized. You can achieve this by adding an additional field in your translations:</p>
<pre><code class="lang-javascript">{
  <span class="hljs-string">"en"</span>: { <span class="hljs-string">"logoAlt"</span>: <span class="hljs-string">"Company Logo"</span> },
  <span class="hljs-string">"fr"</span>: { <span class="hljs-string">"logoAlt"</span>: <span class="hljs-string">"Logo de l'entreprise"</span> }
}

Then bind the localized alt text dynamically
</code></pre>
<pre><code class="lang-javascript">
&lt;img src={imagePath} alt={translations[$locale].logoAlt} /&gt;
</code></pre>
<h4 id="heading-switching-svg-content-dynamically"><strong>Switching SVG Content Dynamically</strong></h4>
<p>If you need to localize content within SVGs, such as text or icons or want to <a target="_blank" href="https://www.adobe.com/express/feature/image/convert/svg">convert to SVG</a> format, consider using Svelte's templating for seamless integration.</p>
<pre><code class="lang-javascript">&lt;svg&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">text</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"20"</span>&gt;</span>{$t('svgText')}<span class="hljs-tag">&lt;/<span class="hljs-name">text</span>&gt;</span></span>
&lt;/svg&gt;
</code></pre>
<p>This approach ensures your SVGs are directly rendered with localized text.</p>
<h3 id="heading-handling-multiple-forms-of-pluralization">Handling Multiple Forms of Pluralization</h3>
<p>While many languages have two forms of plurals (singular and plural), there are many languages with more than two forms, and some don’t pluralize. For example:</p>
<ul>
<li><p>Arabic has six forms</p>
</li>
<li><p>Japanese doesn't pluralize in the same way</p>
</li>
</ul>
<p>We can easily handle these differences using svelte-i18n's ICU message syntax. I’ve also added an example of how you can handle more than two forms when using Arabic.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// src/locales/en.json</span>
{
  <span class="hljs-string">"items"</span>: {
    <span class="hljs-string">"count"</span>: <span class="hljs-string">"{count, plural, =0 {No items} one {1 item} other {{count} items}}"</span>
  }
}

<span class="hljs-comment">// src/locales/es.json</span>

{
  <span class="hljs-string">"items"</span>: {
    <span class="hljs-string">"count"</span>: <span class="hljs-string">"{count, plural, =0 {Sin elementos} one {1 elemento} other {{count} elementos}}"</span>
  }
}

<span class="hljs-comment">// src/locales/ar.json</span>
{
  <span class="hljs-string">"items"</span>: {
    <span class="hljs-string">"count"</span>: <span class="hljs-string">"{count, plural, =0 {لا عناصر} one {عنصر واحد} two {عنصران} few {# عناصر} many {# عنصر} other {# عنصر}}"</span>,
  }
}
</code></pre>
<p>Now, let's create the pluralization component for our Svelte app where a button increments the count with every click.</p>
<pre><code class="lang-javascript">&lt;!-- src/lib/ItemCounter.svelte --&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">import</span> {  } <span class="hljs-keyword">from</span> <span class="hljs-string">'svelte-i18n'</span>;
  <span class="hljs-keyword">let</span> count = <span class="hljs-number">0</span>;
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{$('items.count', { count })}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">on:click</span>=<span class="hljs-string">{()</span> =&gt;</span> count++}&gt;Add Item<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">on:click</span>=<span class="hljs-string">{()</span> =&gt;</span> count--} disabled={count === 0}&gt;Remove Item<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
</code></pre>
<p>With this implemented, your app is fully ready to handle pluralization dynamically (as you’ll notice by clicking on the <strong>Add item</strong> button). </p>
<h3 id="heading-handling-missing-translations">Handling Missing Translations</h3>
<p>Sometimes, translations for certain keys might be missing. This can happen due to oversight, dynamic content, or incomplete translation files. To handle such scenarios gracefully, set up error handling using the <strong>missingKeyHandler</strong> option in <strong>svelte-i18n</strong>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { register, init } <span class="hljs-keyword">from</span> <span class="hljs-string">'svelte-i18n'</span>;

register(<span class="hljs-string">'en'</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./locales/en.json'</span>));
register(<span class="hljs-string">'es'</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./locales/es.json'</span>));

init({
  <span class="hljs-attr">fallbackLocale</span>: <span class="hljs-string">'en'</span>,
  <span class="hljs-attr">initialLocale</span>: <span class="hljs-string">'en'</span>,
  <span class="hljs-attr">missingKeyHandler</span>: <span class="hljs-function">(<span class="hljs-params">locale, key</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.warn(<span class="hljs-string">`Missing translation: <span class="hljs-subst">${key}</span> (<span class="hljs-subst">${locale}</span>)`</span>);
    <span class="hljs-keyword">return</span> key; <span class="hljs-comment">// Display the key itself when translation is missing</span>
  }
});
</code></pre>
<p>This code logs a warning when a translation is missing and displays the key instead of showing nothing.</p>
<h2 id="heading-making-your-app-production-ready">Making Your App Production-Ready</h2>
<p>When preparing your app for real-world users, optimize it for localization by automatically detecting the user’s language. </p>
<p>You can use the browser’s <strong>navigator.language</strong> property to set the initial locale:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { init, getLocaleFromNavigator } <span class="hljs-keyword">from</span> <span class="hljs-string">'svelte-i18n'</span>;

init({
  <span class="hljs-attr">fallbackLocale</span>: <span class="hljs-string">'en'</span>,
  <span class="hljs-attr">initialLocale</span>: getLocaleFromNavigator(),
});
</code></pre>
<h2 id="heading-best-practices-for-scaling-your-localization">Best Practices for Scaling Your Localization</h2>
<ul>
<li><p><strong>Organize translations</strong>: Group related translations logically (for example, buttons, menus, notifications) and use consistent naming patterns for keys.</p>
</li>
<li><p><strong>Use a translation management platform:</strong> As your app grows, handling translation files manually starts becoming cumbersome. <a target="_blank" href="https://centus.com/">Translation management platforms</a> are purpose-built to solve this exact issue and help save hours every day, make it easy to collaborate on projects, and keep track of progress.</p>
</li>
<li><p><strong>Thorough testing</strong>: Test your app with real users across all supported languages. You also need to keep in mind the text length changes to avoid issues with layouts, especially with languages like German or Arabic, which can expand text significantly.</p>
</li>
<li><p><strong>Cultural considerations</strong>: Adapt your app for cultural norms, reading directions (for example, RTL for Arabic), and regional preferences (for example, date and currency formats). </p>
</li>
</ul>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Localization might feel like a big task at first, but it’s totally worth it. It lets you reach more people and makes your app more inclusive.</p>
<p>Svelte and svelte-i18n streamline the process and keep it fun as you build your skills.</p>
<p>To keep it simple, start with the basics, such as adding translations and a language switcher. Advanced features like handling dates, currencies, and pluralization can follow as you gain confidence. </p>
<p>Take your time, test thoroughly, and build an app that feels natural for all the users you serve!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build an MVP for Your Project – and Why You Should Do It ]]>
                </title>
                <description>
                    <![CDATA[ Proof of concept, prototypes, wireframes, mockups… what actually constitutes a Minimum Viable Product (MVP)? Well, it's a product with just enough features to gather comprehensive qualitative feedback. In practice, it's as easy to understand the conc... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/minimum-viable-product-between-an-idea-and-the-product/</link>
                <guid isPermaLink="false">66be14c2b712ab343b0b912f</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mvp ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oleh Romanyuk ]]>
                </dc:creator>
                <pubDate>Fri, 24 May 2024 13:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/02/MVP-as-a-Bicyle.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Proof of concept, prototypes, wireframes, mockups… what actually constitutes a Minimum Viable Product (MVP)?</p>
<p>Well, it's a product with just enough features to gather comprehensive qualitative feedback.</p>
<p>In practice, it's as easy to understand the concept of an MVP as it is to ride a bicycle. Let's do it then.</p>
<p>In this article, I am going to explain:</p>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-an-mvp">What is an MVP?</a></li>
<li><a class="post-section-overview" href="#heading-the-benefits-of-an-mvp">The benefits of an MVP</a></li>
<li><a class="post-section-overview" href="#how-mvp-software-development-is-conducted">How is an MVP developed?</a></li>
<li><a class="post-section-overview" href="#how-would-an-mvp-be-developed-if-it-was-a-bicycle">How would an MVP be developed if it was a bicycle?</a></li>
<li><a class="post-section-overview" href="#heading-why-is-an-mvp-important">Why is it important to build an MVP?</a></li>
<li><a class="post-section-overview" href="#heading-do-you-have-an-idea-for-an-mvp">Do you have an idea for an MVP?</a></li>
<li><a class="post-section-overview" href="#heading-faq">FAQ</a></li>
</ul>
<p>All your customers want to be heard and understood. In the world of software, there is a large number of apps and websites out there, but only a few get the attention and love of the users. So you can start by creating a minimum viable product to find out if your idea has a place in this competitive environment.</p>
<p>Building an MVP doesn’t really cost much. And it helps you investigate the market competition with minimum time and budget loss (in the worst case). You’ll discover the whole story, from benefits and prototype types to the common example of your future developed MVP. So…what are you waiting for?</p>
<h2 id="heading-what-is-an-mvp">What is an MVP?</h2>
<p>The most basic version of a product that can be released to test a business idea is called a minimum viable product (MVP). This concept was popularised by Eric Ries in The Lean Startup. It is part of the ethos of the <a target="_blank" href="https://theleanstartup.com/">Lean Startup</a> methodology. With minimal initial investment, this framework focuses on efficiency and learning from customer feedback.</p>
<p>An MVP is a perfect opportunity to let your potential users voice their opinions and test out a product before its final launch. Gathering and analyzing qualitative feedback is a primary task of MVP development. Based on these findings, you can modify your MVP and test it again.</p>
<p>This process turns into a cycle of MVP product development which takes place over and over again until the ultimate customer satisfaction is reached.</p>
<p>MVPs are all about testing product ideas, analyzing user feedback, and building a full product version based on what you learn. Experts say that it's not an MVP until you can sell it in the B2B world. However, before diving into the process of how to manage an MVP, let’s learn about its main benefits.</p>
<h2 id="heading-the-benefits-of-an-mvp">The Benefits of an MVP</h2>
<p>All these benefits demonstrate a strategic approach that goes far beyond just cost savings and speed to market. It's about smart, customer-centric development, where each iteration brings a product closer to the heart of what users want. </p>
<p>Here are some of the many benefits of building an MVP:</p>
<h3 id="heading-1-product-hypothesis-validation">1. Product Hypothesis Validation</h3>
<p>You can test hypotheses directly with MVPs. MVPs help test the market's response to a product by focusing on building core features. This process helps founders refine their business model with real-world insights rather than guesswork.</p>
<h3 id="heading-2-minimising-capital-investment">2. Minimising Capital Investment</h3>
<p>The development of an MVP requires less investment than the launch of a fully developed end product. This approach aligns with the Lean Startup methodology, which stresses the importance of using just enough features to demonstrate the concept without overburdening resources. It allows startups to allocate their budget more effectively and mitigate financial risks.</p>
<h3 id="heading-3-getting-investors-to-trust-and-get-funded">3. Getting Investors to Trust and Get Funded</h3>
<p>Presenting a well-developed MVP is often crucial to attracting investor interest and raising venture capital funding. The demonstration of a working MVP helps angel investors and venture capitalists visualize the potential of a business idea, making it easier to secure start-up funding.</p>
<h3 id="heading-4-refine-for-product-market-fit">4. Refine for Product-Market Fit</h3>
<p>An MVP is an ideal tool for refining product-market fit, which is a dynamic process. It allows startups to closely align their product with market needs, based on user feedback. This ensures that the final product is well-received by its target audience, increasing the potential for success.</p>
<h3 id="heading-5-gather-customer-feedback">5. Gather Customer Feedback</h3>
<p>The key to the success of any business is gathering feedback from customer research. An MVP provides a platform for engaging early adopters and gathering valuable feedback with a focus on core features.</p>
<p>Such user feedback is critical for startups to understand customer needs and preferences, prioritize the product roadmap, and develop the product for greater market penetration.</p>
<p>Now, you are ready to face the question: “How do you manage MVP software development?”.   </p>
<p><img src="https://lh7-us.googleusercontent.com/baDuR-1JR0cpX5OEJK2ZQL7XY5EK6NKqSDi2eM_MzY91XOscOxKH0BHxGSDbUKc5q_Hi4sWiSNcSm529yP3Vll5v4MDITVXy8iYWCtOvLz0GVutglkk5PD-mOfqZQliFTMgBae01DuaQPP9eC5n93uk" alt="Image" width="600" height="400" loading="lazy">
<em>Stages of MVP development</em></p>
<h2 id="heading-how-to-do-mvp-software-development">How to Do MVP Software Development</h2>
<p>Every product is different, and so is the process of its development. Before we jump into the details of how an MVP is created, I want to point out that it is an individual and iterative process.</p>
<h3 id="heading-product-discovery">Product Discovery</h3>
<p>Your first task is to make your idea come to life. You can start by running product discovery. You need to study the needs, interests, and demographic characteristics of the target audience. Also, analyze the strengths and weaknesses of competitors.</p>
<p>You will then need to go through all the features that can be implemented and select the essential ones. The next thing is to organize this information and present it during the workshops with the help of graphs, charts, tables, or any other form of visualization that you feel best represents the data.</p>
<p>Now, your idea should seem clearer but it is still not presentable.</p>
<h3 id="heading-proof-of-concept">Proof of Concept</h3>
<p>Next, you need to create a Proof of Concept. Basically, this is aimed at summarizing the discovery stage and verifying that your innovative idea can be implemented in real life.</p>
<p>Ok, you know that your idea is feasible and comprehensive. You know that it can be done – but how?</p>
<h3 id="heading-user-journey">User Journey</h3>
<p>Now you need to understand what the user wants to see once they open the application. One of the starting points for an MVP is having a strong sense of your customer. Startups should carefully build a target user profile, taking into account various factors that affect buying decisions and product usage. </p>
<p>To build this target user profile, you have to identify the following:</p>
<ul>
<li>Industry: the type of sector your product serves.</li>
<li>Pain problems: challenges your product aims to solve.</li>
<li>Buying decisions: How they make their decisions and what channels they prefer to use.</li>
<li>Contexts: In which way they would use your product.</li>
</ul>
<p>To do this, you need to map a user journey. User journeys are a visual representation of a potential user and their experience with your app. They cover everything from the moment the user realizes they need this service, to the moment they first find and click through to your app, to the moment they decide to make this service part of their lifestyle.</p>
<p>User journeys resemble a set of statements, which look something like this:</p>
<p><em>As a [user role], I want to do [functions] so that [goal].</em></p>
<p>For example, "As a website admin, I want to be able to add or remove users to keep the app free of spammers". Or, "As an unregistered user, I want to be able to open a menu so I can understand what the application offers before I sign up.”</p>
<h3 id="heading-prototype">Prototype</h3>
<p>After that, it's time to start prototyping. A prototype is a simplified version of the product. It demonstrates the final product design and navigation. Basically, it is a set of pictures of the interface of your future app. If it is clickable, you can navigate between screens by clicking buttons to understand user flows. </p>
<p>Prototypes may even look like a very basic version of your platform or mobile app. It is not a final product and not an MVP because you cannot show it to actual users.</p>
<p>Here, you have your idea implemented. Kind of. It can be shown to all the stakeholders but not to the end user as long as it is just a rough draft. </p>
<p>Now comes the most interesting part: you have to decide the type of MVP you’re going to use. We’ll take a look only at the 5 most popular types (but there are more). So, here we go:</p>
<h4 id="heading-wizard-of-oz-mvp">Wizard of Oz MVP</h4>
<p>This approach gives the user the illusion of a service or product that runs without any human interference – but in reality, behind the scenes, it's all done manually by people. </p>
<p>For example, for developing a digital assistant app, the staff will manually answer the customer instead of complex AI infrastructure. The MVP will allow you to check the standards and collect suggestions from users to make improvements without a big initial input.</p>
<h4 id="heading-concierge-mvp">Concierge MVP</h4>
<p>Similar to the Wizard of Oz MVP, the Concierge MVP is a front for the final automated response of a manually transformed customized service. </p>
<p>For example, if your startup is a food delivery app, you can start by doing order and delivery management manually, rather than building a highly automated platform from the beginning. This is particularly important in customer satisfaction in industries that derive value from personalization and a human touch.</p>
<h4 id="heading-single-feature-mvps">Single-feature MVPs</h4>
<p>In the beginning, you shouldn't try to put together a product with too many features. Instead, develop and release just a single core feature that solves a problem. This will allow you to quickly test the pricing proposition of the product and gather customer feedback for improvements. </p>
<p>In general, prioritizing central functions can speed up development and reduce the likelihood of building redundant skills.</p>
<h4 id="heading-pre-order-mvp">Pre-Order MVP</h4>
<p>This involves placing pre-orders before developing or producing an actual product. With interest and pre-order funding, early sales can be used to help generate visibility and improve the product. This method reduces the chance of developing something that is not going to fit into the market and is perfect for fast iterations based purely on real names.</p>
<h4 id="heading-minimum-viable-demos">Minimum Viable Demos</h4>
<p>You can also put something together that demonstrates your central price proposition but isn’t a totally functional product. This could be a model, a prototype, or an interactive presentation that shows what the product could do, rather than reserving funds for full improvements.</p>
<p>A basic live demo will allow you to make sales to traders, get initial stakeholder comments, and test the market functionality of your idea. This is a very strong way to test concepts before committing any resources to development.</p>
<p>As soon as you have all the info we can continue our journey. This is only a beginning. So, let’s take a look at the next phase.</p>
<h3 id="heading-minimum-viable-product-development">Minimum Viable Product Development</h3>
<p>At this stage, you need to make some ultimate decisions about the UI/UX and finalize the visual design. After that, it's time to start coding the minimum viable product. </p>
<p>The Minimum Viable Product looks like a final app and feels like a final app. But it has fewer features, the design or performance is not necessarily production quality, and the code quality may be lower. Your idea is presented, you've put in the code, and it's partially implemented – it's now ready to meet its first user.</p>
<h3 id="heading-minimum-viable-product-launch-and-testing">Minimum Viable Product Launch and Testing</h3>
<p>After you finish development and launch the MVP, you should present it to a sample set of actual users. Throughout the next few days or weeks, you'll gather customers’ feedback, analyze the results, and modify your MVP accordingly.</p>
<p>Once you see that your customers are fully satisfied, you can start implementing the final product.</p>
<h2 id="heading-example-of-developing-an-mvp-lets-build-a-bicycle">Example of Developing an MVP – Let's Build a Bicycle</h2>
<p>Let’s imagine that you want to create a bicycle. A cool, stylish, hardwearing, and sustainable bike. But what if a potential client can't figure out what you have in mind and you lose all your hard work? What if you need cash and you have to convince your investors that your idea is viable? Well, it's time to build an MVP.</p>
<p>The development process will be pretty similar to what I described earlier. So let's go through it with this example product to see how everything works.</p>
<h3 id="heading-product-discovery-1">Product Discovery:</h3>
<p>You conduct a discovery stage: learn about what a bike is, what parts it consists of, what bikes people like, and what riders complain about. How can you make your bike stand out? </p>
<p>Through studies and marketplace evaluation, you discover insights into customer alternatives and pain points, and lay the groundwork for using new techniques. After that, you answer the most important question: what you can do to make your bicycle stand out among all the others?</p>
<h3 id="heading-proof-of-concept-1">Proof of Concept:</h3>
<p>Let’s say you found out how to create a bicycle chain that never falls off the chain ring. Once you have a clear idea of how to do this, you create your mechanism: a chain, with a chainring and pedals – your proof of concept. </p>
<p>With a clean idea in hand, throw your concept out there to investors. You tell them more about your idea, and receive their approval and support to keep going with the project.</p>
<h3 id="heading-prototype-1">Prototype:</h3>
<p>But it's not quite time to build the final bicycle, as you have not seen it yet in its actual size. So now you create a full-scale copy of the bicycle, carefully choose all the colors and materials, and make it resemble a real product.</p>
<p>Still, the pedals won’t spin yet, and you won't be able to steer or actually ride it. This is your prototype – looks pretty impressive and realistic but does not work yet.</p>
<h3 id="heading-mvp-development">MVP Development:</h3>
<p>Your investors again review the idea and approve your design, but now they need to see the functionality. You again create a full-scale bicycle, and now it has working wheels, pedals, brakes, gears, and a seat. That is going to be your MVP.</p>
<p>At this point, you can let your users try it out. They get on a bike, test it, and share their opinion with you. The more people try it, the more complete your feedback is. Just be sure not to show your bicycle to people you do not trust, or they might leak your idea to a next-door producer who also makes bikes for a living.</p>
<h3 id="heading-mvp-testing">MVP Testing:</h3>
<p>Finally, you modify your product based on what your customers have to say until you are sure that you've got it right. Each improvement brings you closer to perfection, ensuring your bike meets and beats expectations. Through rigorous testing and iteration, you build a product that not only meets your goals but also delights with functionality and format.</p>
<h3 id="heading-final-product-development">Final Product Development:</h3>
<p>Only after all these steps, when you have received financial support from your investors and the approval of your customers, are you ready for the launch.</p>
<p>You change out the wooden seat for a cushioned one, install safety lights on your bicycle, lubricate the bicycle chain, put on stickers and a bell, and start selling your product. A strong advertising and promotional campaign announces the arrival of your product. The culmination of creativity and hard work marks the start of a new technology in the world of cycling.</p>
<h2 id="heading-why-is-an-mvp-important">Why is an MVP Important?</h2>
<p>A Minimum Viable Product has one main advantage, but it's a very important one: it allows you to test your future product in real-life settings with actual users.</p>
<p>This simple benefit has a lot of positive consequences:</p>
<ul>
<li>An MVP lets you adjust your product development plan before it's too late.</li>
<li>It serves as a warning for any mistakes you make or as confirmation for good business decisions.</li>
<li>This approach saves you a great deal of time, effort, and money by optimizing the planning process and reducing risks.</li>
<li>A Minimum Viable Product boosts motivation because the team knows that what they do matters.</li>
<li>MVP development offers a unique experience of testing the product idea, which will definitely come in handy in your professional life in the future.</li>
<li>The MVP approach can and should be used within industries of all sorts. While for manufacturers of traditional goods it's a long and strenuous process, for software developers it can be rather simple and accessible.</li>
</ul>
<p>Some businesses may choose to disregard the minimum viable product stage when creating something innovative – and that may be understandable in certain spaces. But in my opinion, for a software development company it's detrimental.</p>
<p>Once a team has launched a Minimum Viable Product, they can decide whether the venture is on the right track. The most important outcome of an MVP is to get valuable statistics from early users. It's the customers who provide information about the first-class performance of the project. The statistics you get can be used to plan future improvements and prioritize which features should be implemented first.</p>
<p>If you decide to take a risk and implement your idea before checking in with your target audience, you're potentially placing money, time, effort, energy, inspiration, and supporters on the line.</p>
<h2 id="heading-do-you-have-an-idea-for-an-mvp">Do you have an idea for an MVP?</h2>
<p>My company Covent IT is experienced in developing Minimum Viable Products. In case you need a free estimate for a similar project, feel free to <a target="_blank" href="https://keenethics.com/contacts?activeform=estimate">get in touch</a><em>.</em> </p>
<p>If you have enjoyed the article, you should continue with <a target="_blank" href="https://coventit.com/blog/How-IT-Outsourcing-Saves-Costs">How IT Outsourcing Saves Costs for Your Company</a> and <a target="_blank" href="https://coventit.com/blog/risks-of-it-outsourcing">Avoiding Pitfalls in IT Outsourcing: Tips for Minimizing Risks</a>.</p>
<h2 id="heading-faq">FAQ</h2>
<h3 id="heading-how-to-spend-fewer-resources">How to spend fewer resources</h3>
<p>Remember that you should create an MVP with a minimum of time, money, and effort. Think about how you can spend less and still effectively test your business idea. Discussing this question will usually help you choose the MVP functionality to implement in the early stages of new product development.</p>
<h3 id="heading-how-do-you-interact-with-users">How do you interact with users?</h3>
<p>One of the main goals of creating an MVP is to test your hypotheses and determine the need and value of the product. Feedback from the first users of the product helps you achieve this goal. In order not to miss any important information, think about how you will interact with the target audience: through reviews, surveys, direct interviews, and so on.</p>
<h3 id="heading-how-do-you-make-the-first-sales-of-a-product">How do you make the first sales of a product?</h3>
<p>The first sales of the product will give you the means to develop it further and to see if there is interest in your product. You could also consider organizing a pre-sale on a crowdfunding platform such as Kickstarter.</p>
<h3 id="heading-how-do-you-promote-a-product">How do you promote a product?</h3>
<p>Plan the promotion campaign and the channels you will use. Google Adwords is usually the main tool. Then choose social networks (Facebook, Instagram, and so on), create official pages, and start targeting. You can also collect feedback on social networks.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Infinite Pagination in Flutter with Firebase, Riverpod, and Freeze ]]>
                </title>
                <description>
                    <![CDATA[ By Rutvik Tak When you're developing an app, you'll have to decide how you want to load data. And this will typically bring up the issue of infinite pagination.  You likely won't be showing all of the available items in your DB to your users. You may... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/infinite-pagination-in-flutter-with-riverpod/</link>
                <guid isPermaLink="false">66d460c7230dff0166905867</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 14 Apr 2022 23:46:42 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/03/Firebase-Security-Rules-Introduction--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Rutvik Tak</p>
<p>When you're developing an app, you'll have to decide how you want to load data. And this will typically bring up the issue of infinite pagination. </p>
<p>You likely won't be showing all of the available items in your DB to your users. You may fetch the first 10-20 items and load the next ones as the user scrolls. </p>
<p>This not only saves you unnecessary reads on your database, but also improves performance as you're loading items on demand.  </p>
<p>Getting this right is crucial if you're trying to build high-quality apps. I had the chance to work on a B2B application for one of my clients, and having a nice pagination experience was critical to our application – both in terms of fetch operations and user experience.</p>
<p>In this tutorial, I'll walk you through the approach I took so you can build this feature in your own apps.  </p>
<p>This article is focused toward readers who already have a basic understanding of Flutter Slivers, Firebase, Riverpod, and Freezed and who want to use them to build something cool. </p>
<p>This is less like a tutorial and is rather something I wanted to share which I think is an interesting take on pagination implementation with these packages. </p>
<p>Once you understand the reasons behind these implementations, then you may be able to replicate this with other state management and DB solutions of your choice. </p>
<p>Also, I've tried to make things as clear as possible while staying within the scope of the article and have added links for supporting articles/documentation to follow up with.</p>
<h2 id="heading-what-well-cover-here">What we'll cover here:</h2>
<ol>
<li>Overview of tools/packages we are using</li>
<li>Feature Breakdown</li>
<li>How to fetch and limit items</li>
<li>How to fetch data as we scroll</li>
<li>How to cache or store fetched items</li>
<li>How to manage OnGoingStates</li>
<li>Some improvements you can make</li>
</ol>
<h2 id="heading-here-are-the-tools-and-packages-well-be-using">Here are the tools and packages we'll be using:</h2>
<ul>
<li><strong><a target="_blank" href="https://firebase.google.com/docs/firestore">Cloud Firestore</a>:</strong> NoSQL database solution from Firebase.</li>
<li><strong><a target="_blank" href="https://riverpod.dev/">Riverpod</a>:</strong> a state management library from the author of Provider.</li>
<li><strong><a target="_blank" href="https://pub.dev/packages/freezed">Freezed</a>:</strong> a code generator for unions/pattern-matching/copy. Commonly used for generating class models with from and to json methods. </li>
</ul>
<p>And here's the source code if you'd like to have a look: <a target="_blank" href="https://github.com/rutvik110/infinite_pagination">Infinite pagination in Flutter with Riverpod, Freezed, Firebase</a>.</p>
<h2 id="heading-feature-breakdown">Feature Breakdown</h2>
<p>To make things easier to understand and work with, I always try to break them down into their different states. This way, you'll get the abstract idea of what's going on and we can handle each task one by one so we don't get overwhelmed.  </p>
<p>Our Pagination feature has the following different states:</p>
<h3 id="heading-initial-fetch-states">Initial fetch states</h3>
<p>Here are what the Loading, Data, and Error states should look like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/loadingState-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Initial loading</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/dataState-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Data loaded</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/errorState-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Error state</em></p>
<h3 id="heading-ia"> </h3>
<p>After first fetch states (OnGoingStates)</p>
<p>Here are what the OnGoingLoading, OnGoingData, and OnGoingError states should look like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/onGoingLoadingState-3.gif" alt="Image" width="600" height="400" loading="lazy">
<em>OnGoingLoading state</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/onGoingDataState-2.gif" alt="Image" width="600" height="400" loading="lazy">
<em>OnGoingData state</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/onGoingErrorState-2.gif" alt="Image" width="600" height="400" loading="lazy">
<em>OnGoingError state</em></p>
<p>Alright now that we've seen what our different states will look like, let's dive in.</p>
<h2 id="heading-how-to-fetch-and-limit-data">How to Fetch and Limit Data</h2>
<p>I got a sample application running – it does nothing special except fetching the data as it is from Firebase. </p>
<p>We are using <a target="_blank" href="https://docs.flutter.dev/development/ui/advanced/slivers">Slivers for scrolling</a> behaviour and we are using <a target="_blank" href="https://riverpod.dev/docs/concepts/reading/#consumer-and-hookconsumer-widgets">Consumer from Riverpod</a> to load the data through a future provider that's fetching items from Firebase. I've already added some data in Firebase (*Firestore), so we'll just be using that.</p>
<p>Loading the items through Consumer:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/initial_paginatedview-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Loading initial items through a consumer using Slivers</em></p>
<p>Declaring Providers:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/init_providers.png" alt="Image" width="600" height="400" loading="lazy">
<em>Declaring database class provider and the futureProvider that returns the items from the database.</em></p>
<p>MyDatabase class:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/MyDatabase_initiali.png" alt="Image" width="600" height="400" loading="lazy">
<em>Database class with a method called fetchItems() which fetches the items from a Firestore collection called "items" and returns them.</em></p>
<p>Here's a preview of what this will look like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/fetching_all_items-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Loading items from Firebase into the app. Showing initial loading, ondata states.</em></p>
<p>As you can see, we are fetching everything that's available, which is not very good! We want to limit the number of items we fetch. </p>
<p>We can do that by using <strong><code>.limit(n)</code></strong> on our Firebase query. We'll set that limit to 20 items and order our items by <strong>createdAt</strong> field in descending order. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/limiting_items.png" alt="Image" width="600" height="400" loading="lazy">
<em>Limiting the number of items fetched with the help of .limit(n) and ordering items based on "createdAt" value.</em></p>
<p>Now, we only fetch the most recent 20 items from our database. 🙌   </p>
<p>Ordering items with respect to some field that is unique and which can be used to sort is important here. This is one of the ways to paginate items. This is also called cursor-based pagination.</p>
<h3 id="heading-how-to-add-the-mechanism-for-scrolling-callback">How to Add the Mechanism for Scrolling Callback</h3>
<p>To get the information on the scrolling, we'll create a ScrollController and pass it to our CustomScrollView.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/adding_scroll_controller-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Added ScrollListener and listening to scroll events to make a call when scroll position is near the end of the items list.</em></p>
<ul>
<li><strong>maxScroll</strong>: Maximum amount of distance the user can scroll in the scrolling axis.</li>
<li><strong>currentScroll</strong>: Current position of the user in the scrolling view.</li>
<li><strong>delta</strong>: Amount of space from the bottom.</li>
</ul>
<p>We'll listen to scrolling events, and when the difference between <strong>maxScroll</strong> and <strong>currentScroll</strong> gets less than the <strong>delta</strong>, we make the call to fetch the next batch of items.</p>
<h2 id="heading-how-to-store-and-fetch-the-next-batch">How to Store and Fetch the Next Batch</h2>
<p>This will be interesting. Let's see what we have to manage here:</p>
<ol>
<li>How to store already-fetched items.</li>
<li>How to build up logic to fetch the next batch of items based on what we fetched previously.</li>
</ol>
<p>To manage these two functionalities, we'll use <a target="_blank" href="https://riverpod.dev/docs/providers/state_notifier_provider/">StateNotifiersProvider</a> in Riverpod. Using them will help us separate our core implementation logic from the UI layer and give us more flexibility in handling different states of fetching and building up logic for the fetch calls.</p>
<p>This is also Riverpod's recommended solution for managing state which may change in reaction to user interaction.</p>
<p>Here's the updated itemsProvider:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/itemsProvider.png" alt="Image" width="600" height="400" loading="lazy">
<em>Updated itemsProvider to StateNotifierProvider which creates a PaginationNotifier with initial items count and fetchNextItems call back.</em></p>
<p>Here's PaginationStateNotifier:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/paginated_state_notifier-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>PaginationNotifier that will hold fetched items and handle all the logic related to different pagination states and fetch callbacks.</em></p>
<p>In this code, we created our <strong>PaginationNotifier</strong> by extending it to the StateNotifier class. We made it generic representing the type with <strong>T</strong> to make it reusable. </p>
<p>So, let me go through things in here:</p>
<ul>
<li><strong>_items</strong>: All the fetched items are added to this list.</li>
<li><strong>itemsPerBatch</strong>: Max number of items in a batch. Same as the number we set in the limit on the firebase query in the backend.</li>
<li><strong>fetchItems (T? item)</strong>: This function will be the one actually making the call to fetch the items, and it accepts a nullable item. This <strong>item</strong> is the last item from the <strong>_items</strong> list. If it's the first time we are fetching items or <strong>_items</strong> is empty, then it'll be <strong>null</strong>. </li>
<li><strong>fetchFirstBatch()</strong>: Will fetch the first batch of items and update the state.</li>
<li><strong>fetchNextBatch()</strong>: Will fetch the next batch of items and update the state. The implementation is almost the same as the <strong>fetchFirstBatch</strong> right now except for two important things:<br>– At first, we are updating the state to <strong>.data(_items)</strong>. This is because we still want to show the previously fetched items while the next batch is loading.<br>– Second, we pass the last item in the <strong>_items</strong> list when making the call to fetch items. This section will improve in the next section where we'll add OnGoingStates to handle this better.</li>
<li><strong>init()</strong>: Called when the notifier is initialized. We just make the call to fetch the first batch here if the items are empty.</li>
</ul>
<p>Now, let's see what we have to update in the backend logic:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/MyDatabase_final-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Database class fetchItems method updated for fetching next 20 items based on the last item fetched.</em></p>
<p>So we are accepting an item here now. If the item is null, we fetch the first 20 items. If it's not, then we are using a <strong>.startAfter()</strong> filter on our query, which basically says, "Hey! I want the items that start after the item that matches this value that I'm sending along. Cool!"</p>
<p>A bit more professional answer here: 😅</p>
<blockquote>
<p><a target="_blank" href="https://firebase.google.com/docs/firestore/query-data/query-cursors">startAfter()</a>: Takes a list of [values], creates and returns a new [Query] that starts after the provided fields relative to the order of the query. (From the Firebase docs)</p>
</blockquote>
<p>On the UI side, we won't have to change anything. Let's run this and see what we get!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/ezgif.com-gif-maker.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Loading next items on demand as user scrolls towards end of the items list.</em></p>
<p>Nice! We are loading up the next batches as we scroll toward the end of the list. Isn't that cool? 😁</p>
<p>Now we want to work on the display. We want to show an ongoing loading or error indicator at the bottom of our list which will represent OnGoingStates.</p>
<h2 id="heading-how-to-manage-ongoing-states">How to Manage OnGoing States</h2>
<p>So how do we manage these OnGoingStates and represent them to the user?  </p>
<p>Well, this doesn't have a single answer. One approach is to create some variable within StateNotifier that represents these states in enum form and updates them to indicate the OnGoingStates. This is what I did in my first iteration, and it turned out not to be a very good approach. </p>
<p>So instead, let's jump to the thing that worked for me.  </p>
<p>As we have more than three states to handle here, why don't we create our own version of AsyncValue that will include two more additional states called OnGoingLoading and OnGoingError state? AsyncValue is just a union that maps to different states. We could create something similar.</p>
<p>We can do this by using <a target="_blank" href="https://pub.dev/packages/freezed">Freezed</a>, which is a code generation library for creating unions and a lot more. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/pagination_state.png" alt="Image" width="600" height="400" loading="lazy">
<em>Creating our custom PaginationState union with Freezed.</em></p>
<p>The first three states here are self-explanatory – they're the regular ones that you interact with when using AsyncValue.  </p>
<p>As our OnGoingLoading and OnGoingError states occur after our first call, we also want to display the previously fetched items in this state so we have the items parameter. And an additional error and stack trace parameter for the OnGoingError state.</p>
<p>I believe this way we are more declarative on what we are doing on both the UI and business logic sides. Also, the representation to the user gets pretty easy and clean with this.  </p>
<p>Now, let's update our StateNotifier to use this new PaginationState object instead of AsyncValue.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/adding_ongoing_states-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Updated PaginationNotifier to use PaginationState instead of AsyncValue.</em></p>
<p>In the <strong>fetchNextBatch</strong> function, we'll update our state to <strong>.onGoingLoading</strong> and <strong>.onGoingError</strong> states replacing the <strong>.data()</strong> and <strong>.error()</strong> states.</p>
<p>On the UI side, you'll see some compilation errors. We'll also need to handle these two new states in our Consumer.</p>
<p>Updated PaginatedListView :</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/paginatedlistview-5.png" alt="Image" width="600" height="400" loading="lazy">
<em>Updated UI code for PaginatedListView</em></p>
<p>ItemsList: So, I extracted my logic for loading items in its separate widget.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/itemslist.png" alt="Image" width="600" height="400" loading="lazy">
<em>Updated UI code for ItemsList now handling both initial and OnGoing states.</em></p>
<p>ItemsListBuilder: And the logic for building out items list or SliverList is extracted into its own widget as well which makes it reusable across different pagination states.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/itemslistbbuilder.png" alt="Image" width="600" height="400" loading="lazy">
<em>Builder that builds sliver list of items.</em></p>
<p>The final step that remains is adding that loading/error indicator at the bottom of the <strong>ItemsList.</strong> </p>
<p>For this, we'll just add another consumer that will handle only the <strong>OnGoingLoading</strong> and <strong>OnGoingError</strong> states.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/adding_ongoing_bottom_widget.png" alt="Image" width="600" height="400" loading="lazy">
<em>Adding OnGoingBottomWidget below our items list which shows appropriate message based on OnGoing state.</em></p>
<p>There we go! That looks much better.</p>
<p>Let's see it in action in an iOS simulator showing the handing of different ongoing pagination states: 🚀</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/onGoingLoadingState-4.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/onGoingDataState-3.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/onGoingErrorState-3.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-some-improvements-you-can-make">Some Improvements You Can Make</h2>
<p>Now that we have a working application with pagination, the next steps are to improve upon what we have done so far. </p>
<p>That includes things related to limiting our calls to fetch when there's already a fetch call going on, debouncing calls within a certain duration, and letting the user know if they've reached the end of the list and there are no more items to display.</p>
<p>Also, who doesn't want a scroll to the top button 😅.</p>
<h3 id="heading-how-to-reject-concurrent-requests">How to reject concurrent requests</h3>
<p>First, we'll reject any concurrent requests that happen in a certain duration after a request is made. We can do this by creating a timer and checking if that timer is active on each request. If it is, we reject the request or else proceed and again instantiate the timer. </p>
<p>Second, we can also check for our state – if we are already processing the previous request then we reject the incoming request. For this, we can just check if our state is equal to the loading state and handle that.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/adding_timer_with_state_check.png" alt="Image" width="600" height="400" loading="lazy">
<em>Added timer and state check to debounce any immediate calls after a call is made or when state is loading.</em></p>
<h3 id="heading-has-reached-end-of-list-no-more-items-to-fetch">Has reached end of list (no more items to fetch)</h3>
<p>We can maintain a boolean that indicates this. Every time we get our results, we can check if the results are less than our <strong>itemsPerBatch</strong> count. </p>
<p>On the UI side, we can present a proper message based on that. Here's the updated pagination notifier:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/nomoreitems_addition.png" alt="Image" width="600" height="400" loading="lazy">
<em>Declaring a noMoreItems bool to know when there are no more items to fetch.</em></p>
<p>And the updated UI code: </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/noMoreItems.png" alt="Image" width="600" height="400" loading="lazy">
<em>Showing a proper message based on status of noMoreItems bool.</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/nomoreitems.gif" alt="No More Items Found condition!" width="600" height="400" loading="lazy">
<em>No More Items Found demo.</em></p>
<h3 id="heading-how-to-add-a-scroll-to-top-button">How to add a scroll to top button</h3>
<p>These buttons are useful and save the user from a whole bunch of scrolling. Here's how we can implement one in our app: </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/scroll_to_top_button_addition.dart.png" alt="Image" width="600" height="400" loading="lazy">
<em>Adding a ScrollToTopButton</em></p>
<p>We are using AnimatedBuilder to listen for scrolling updates. AnimatedBuilder accepts a listenable object and as our ScrollController is actually a ChangeNotifier that implements Listenable, we can pass it here.</p>
<p>If the <strong>scroll offset</strong> is greater than a certain value, then we show the <strong>ScrollToTop</strong> button. When tapped, we animate the scrolling to the top.  </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/scroll_to_top.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Demo showing usage of ScrollToTopButton added above.</em></p>
<h2 id="heading-summary">Summary</h2>
<p>That wraps it up! Here are some of the things you learned about in this article:</p>
<ul>
<li>How to handle the different states of pagination effectively with Riverpod and Freezed.</li>
<li>How to use the cursor-based pagination technique with Firebase. The same can be applied to whatever DB you're using with only changes in the backend fetch function. Other implementations remains the same. </li>
</ul>
<p><strong>Again, here's the source code:</strong> <a target="_blank" href="https://github.com/rutvik110/infinite_pagination">Infinite pagination in Flutter with Riverpod, Freezed, Firebase</a></p>
<p>Hope you enjoyed the article. ☺️ This was my first article here on freeCodeCamp and I really enjoyed writing this. It took a 😅 lot more time to write than I had imagined but finally, it's here for you to read!🙌 </p>
<p>I hope to write more such articles here 🙇‍♂️ along with some Flutter design 🧑‍🎨 challenges as I myself explore app development as a growing developer and bring interesting stuff to you! 😁</p>
<p>I'm also active on Twitter <a target="_blank" href="https://twitter.com/TakRutvik">@TakRutvik</a> 💙 sharing my creations and things that I've been working on. Feel free to reach out ☺️.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn How to Build Apps From a Business Perspective ]]>
                </title>
                <description>
                    <![CDATA[ There is way more to building successful apps than just coding. In fact, coding is often the easiest part. There are many business considerations that are extremely important. We just published an 8-hour course on the freeCodeCamp.org YouTube channel... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-how-to-build-apps-from-a-business-perspective/</link>
                <guid isPermaLink="false">66b2046a712508eb16067880</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ business ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Mon, 06 Dec 2021 15:37:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/12/apps.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>There is way more to building successful apps than just coding. In fact, coding is often the easiest part. There are many business considerations that are extremely important.</p>
<p>We just published an 8-hour course on the freeCodeCamp.org YouTube channel that will teach you the business of building apps. </p>
<p>Shad Sluiter created this course. He teaches computer science and programming classes at Grand Canyon University.  He has multiple degrees in Computer Science, Mathematics and Education, as well as a Masters degree in Computer Information Systems.</p>
<p>This project management course is for leaders, entrepreneurs, and software developers. You will learn everything from determining what type of app to build, effective app design, marketing and monetization strategies, choosing the right tools, hiring and managing development teams, and more.</p>
<p>Here are all the sections covered in this course:</p>
<h3 id="heading-unit-11-what-is-the-value-proposition-of-your-app">Unit 1.1 What is the value proposition of your app?</h3>
<ul>
<li>Do you need a web app or just a better website?</li>
<li>Categories of Apps – which app category is easiest to compete in?</li>
</ul>
<h3 id="heading-unit-12-identify-the-problem-you-are-trying-to-solve-with-your-app">Unit 1.2 Identify the problem you are trying to solve with your app.</h3>
<ul>
<li>Candy, vitamins or addictive painkiller?</li>
<li>Fulfillment, recognition, security</li>
<li>The Five Whys</li>
</ul>
<h3 id="heading-unit-13-how-to-discover-a-niche-in-the-marketplace">Unit 1.3 How to discover a niche in the marketplace</h3>
<ul>
<li>Follow popular trend </li>
<li>Add a twist </li>
<li>Your own expertise  </li>
<li>Problems in existing competition  </li>
<li>Unit 1.4 Listening to users </li>
<li>Users that exist in the market</li>
<li>Get user feedback</li>
<li>Idea 2.0</li>
<li>Homework 1.1 Airbnb and Lyft</li>
<li>Homework 1.2 App Annie and Sensor Tower</li>
<li>Homework 1.3 Write an application plan</li>
</ul>
<h3 id="heading-unit-2-ui-ux-mvp-design">Unit 2 UI, UX, MVP design</h3>
<ul>
<li>How to create user stories </li>
<li>Planning for an MVP</li>
</ul>
<h3 id="heading-unit-22-designing-an-effective-ui-user-interface">Unit 2.2 Designing an effective UI user interface</h3>
<ul>
<li>On boarding new users</li>
<li>The Google UI Case Study</li>
<li>The Photoshop Adobe UI negative Case Study</li>
<li>Effective UI elements</li>
<li>Don’t Make Me Thing Steve Krug </li>
<li>UI design templates</li>
<li>Design for your target audience</li>
<li>Unit 2.3 How to design an effective UX User Experience</li>
<li>UX is where Design strategy and Technology intersect</li>
<li>Application Flow </li>
<li>Measuring Conversion Rates</li>
<li>UX outside of the app</li>
<li>The User Empathy Map </li>
<li>Six principles for a positive UX</li>
</ul>
<h3 id="heading-unit-24-the-mvp">Unit 2.4 The MVP</h3>
<ul>
<li>The Lean Startup MVP concept by Eric Ries</li>
<li>Planning for future versions of your app</li>
<li>What is NOT an MVP</li>
<li>Zappos MVP Case Study</li>
<li>The MVP design pyramid</li>
<li>The purpose of an MVP</li>
<li>Keeping the cost of an MVP low</li>
<li>Homework 2.1 App Design Case Studies</li>
<li>Homework 2.2 Develop User Stories</li>
<li>Homework 2.3 Interactive UI prototype</li>
</ul>
<h3 id="heading-unit-31-marketing-and-monetization-for-an-app">Unit 3.1 Marketing and Monetization for an App</h3>
<ul>
<li>The BMC Case Study</li>
<li>Unit 3.2 Monetization Strategies of Apps</li>
<li>Apple App Store vs Google Play Store revenue </li>
<li>iOS vs Android user value per customer</li>
<li>iOS vs Android market share in various countries </li>
</ul>
<h3 id="heading-unit-33-marketing-your-app">Unit 3.3 Marketing Your App</h3>
<ul>
<li>How users discover your app</li>
</ul>
<h3 id="heading-unit-34-dealing-with-investors">Unit 3.4 Dealing with Investors</h3>
<ul>
<li>Homework 3.1 Build a BMC for your app</li>
</ul>
<h3 id="heading-unit-41-building-customer-loyalty">Unit 4.1 Building Customer Loyalty</h3>
<ul>
<li>Why Customers Abandon Apps?</li>
<li>First-to-Mind solution</li>
<li>Compulsion</li>
<li>Morality of Addictive Apps</li>
<li>The HOOK app addictive model</li>
<li>Homework 4.1 Understanding Hook</li>
<li>Homework 4.2 Applying Hook</li>
</ul>
<h3 id="heading-unit-51-choosing-the-right-tools">Unit 5.1 Choosing the Right Tools</h3>
<ul>
<li>Five Reasons Not to Build an App</li>
</ul>
<h3 id="heading-unit-52-nine-companies-who-nailed-their-app">Unit 5.2 Nine Companies Who Nailed their App</h3>
<h3 id="heading-unit-53-development-languages-and-cross-platform-tools">Unit 5.3 Development Languages and Cross Platform Tools</h3>
<ul>
<li>Homework 5.1 Compare Dev Tools</li>
<li>Homework 5.2 Recommend a Development Solution</li>
</ul>
<h3 id="heading-unit-61-full-stack-considerations">Unit 6.1 Full Stack Considerations</h3>
<ul>
<li>Choosing a Database Backend</li>
<li>SQL</li>
<li>noSQL</li>
<li>SQL vs noSQL </li>
<li>Graph Database</li>
<li>Full Text Database </li>
<li>Vertical Scaling</li>
<li>Horizontal Scaling</li>
<li>Data Duplication in Distributed Databases </li>
<li>SQL Shards</li>
</ul>
<h3 id="heading-homework-61-recommend-database-solutions">Homework 6.1 Recommend Database Solutions</h3>
<ul>
<li>Homework 6.2 Explore API services</li>
</ul>
<h3 id="heading-unit-71-hiring-the-development-team">Unit 7.1 Hiring the Development Team</h3>
<ul>
<li>Four Roles of a Software Development Team</li>
<li>Product Manager</li>
<li>Product Designer</li>
<li>Front End Developer</li>
<li>Back End Developer</li>
</ul>
<h3 id="heading-unit-72-mobile-vs-web-development">Unit 7.2 Mobile vs Web Development</h3>
<ul>
<li>Skills Used in Mobile vs Web Development</li>
<li>Web vs Mobile Development Salaries</li>
</ul>
<h3 id="heading-unit-73-agile-team-management">Unit 7.3 Agile Team Management</h3>
<ul>
<li>SDLC Agile vs Waterfall</li>
<li>What is Waterfall Development?</li>
<li>What is Agile Scrum Methodology? </li>
<li>The Product Backlog</li>
<li>Spring Planning</li>
<li>Sprint Backlog</li>
<li>What is a Sprint?</li>
<li>Product Increment</li>
<li>Daily Scrum</li>
<li>Sprint Review</li>
<li>Sprint Retrospective</li>
</ul>
<h3 id="heading-unit-74-how-to-write-a-job-requisition">Unit 7.4 How to Write a Job Requisition</h3>
<ul>
<li>Cross Field Expertise</li>
<li>Intangibles</li>
<li>Adjacent Skills</li>
<li>Portfolio</li>
<li>Homework 7.1 Team Roles</li>
<li>Homework 7.2 Internal Job Requisition</li>
<li>Homework 7.3 External Job Posting</li>
</ul>
<h3 id="heading-unit-81-future-trends-in-mobile-development">Unit 8.1 Future Trends in Mobile Development</h3>
<ul>
<li>Cloud Computing</li>
<li>38 Artificial Intelligence</li>
<li>Cross Platform Dev</li>
<li>mCommerce</li>
<li>Virtual Reality</li>
<li>Augmented Reality</li>
<li>Higher Bandwidth</li>
<li>IOT</li>
<li>Wearables</li>
<li>Security</li>
<li>Blockchain</li>
<li>Beacon</li>
<li>Homework 8.1 Review Past Predictions</li>
<li>Homework 8.2 Current State of Development Tools</li>
<li>Homework 8.3 Future Mobile Tech</li>
</ul>
<p>Watch the full course below or <a target="_blank" href="https://www.youtube.com/watch?v=poLzjLt2yqU">on the freeCodeCamp.org YouTube channel</a> (8-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/poLzjLt2yqU" 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>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Best Podcasts for Flutter Developers ]]>
                </title>
                <description>
                    <![CDATA[ By Krissanawat Podcasts are a great way to consume digital information. They've become quite popular because you can listen to them anywhere, any time.  Podcasts deliver educational, entertaining, and engaging content on all kinds of topics – tech to... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/best-podcasts-for-flutter-developers/</link>
                <guid isPermaLink="false">66d46012733861e3a22a7328</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 11 Aug 2021 20:51:56 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/08/photo-1589903308904-1010c2294adc.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Krissanawat</p>
<p>Podcasts are a great way to consume digital information. They've become quite popular because you can listen to them anywhere, any time. </p>
<p>Podcasts deliver educational, entertaining, and engaging content on all kinds of topics – tech topics included. The hosts and their guests talk and share ideas, each in their own way, which makes every podcast different and interesting.</p>
<p>This post is a compilation of some of the best podcast channels available for free that focus on the Flutter framework. </p>
<p>Flutter is a popular cross-platform mobile application development framework that helps you build pixel-perfect UIs powered by the Dart programming language. </p>
<p>Its community is growing rapidly which means that every day there are more resources out there about the framework, like articles, podcasts, libraries, other tools. </p>
<p>The podcasts I've gathered in this article deliver all kinds of Flutter-related content including the journeys of some of the top Flutter experts. You should definitely subscribe and tune into them.</p>
<h2 id="heading-flutter-101-podcast">Flutter 101 Podcast</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-55.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The <a target="_blank" href="https://podcasts.google.com/feed/aHR0cHM6Ly9mZWVkcy5zaW1wbGVjYXN0LmNvbS9lU3labTZKOA==">Flutter 101 Podcast</a> is one of the most popular podcast channels on Flutter. A large numbers of developers listen to it who are actively involved in the Flutter community. </p>
<p>It is a weekly podcast series hosted by Vince Varga and it focuses on Flutter development and its what's going on with the framework. </p>
<p>If you want to get the latest news and updates regarding Flutter development as well as learn the tech itself, then this is a good option for you.</p>
<h2 id="heading-its-all-widgets">It's all Widgets</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-54.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><a target="_blank" href="https://itsallwidgets.com/podcast">It's all Widgets</a> is a popular podcast channel created by Flutter developers from the Flutter community. </p>
<p>Along with all the latest news and updates from the Flutter ecosystem, it also delivers stories from Flutter contributors and practitioners. </p>
<p>The main focus lies in sharing inspiring stories of Flutter developers and how they got into the field. The podcast is hosted by Hillel Coren, Google Developer Expert for FlutterDev.</p>
<h2 id="heading-flying-high-with-flutter">Flying High With Flutter</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-53.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><a target="_blank" href="https://www.youtube.com/watch?v=zknqsZ9c7cI">Flying High with Flutter</a> is a weekly podcast channel that delivers episodes on the Flutter development ecosystem. It discusses anything and everything related to Flutter. </p>
<p>The primary focus is on real-world problems you might face while using Flutter but also includes daydream-inspired and challenging ideas on the Flutter community. </p>
<p>The podcast also invites expert guests in the Flutter field to share their background, experience, thoughts, and insights into the engaging Flutter world.</p>
<h2 id="heading-learning-flutter">Learning Flutter</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-52.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As the name suggests, the <a target="_blank" href="https://player.fm/series/learning-flutter">Learning Flutter</a> podcast channel helps you learn Flutter/Dart programming. </p>
<p>In this Podcast hosted by Wilfried Mbouenda Mbogne, he shares stories about his Flutter adventures as a developer. The podcast also hosts other experts from the Flutter field to share their journeys in the Flutter world. </p>
<p>This podcast can be a source of inspiration for many mobile application developers.</p>
<h2 id="heading-codeon">CodeOn</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-51.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><a target="_blank" href="https://podcasts.google.com/feed/aHR0cHM6Ly9hbmNob3IuZm0vcy81M2YwNDgwMC9wb2RjYXN0L3Jzcw==">CodeOn</a> is a weekly podcast channel hosted by Tulsiram Mehtre, a GoogleDevExpert. His main goal is to help developers build high-quality applications quickly and efficiently. </p>
<p>This podcast channel not only delivers knowledge on Flutter but also covers intermediate to advanced lessons about JavaScript, Angular, Firebase, and modern app development. So you are getting the whole package each week.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>The main goal of this article was to introduce you to some of the best podcast channels available for the Flutter development ecosystem. </p>
<p>I hope it's an invaluable resource for any mobile app developers out there. I recommend everyone to subscribe and tune in to these amazing Flutter-based podcasts to get up-to-date knowledge and understanding of the Flutter world.</p>
<p>Lastly, you can get inspiration for your <a target="_blank" href="http://instaflutter.com/">Flutter app</a> from others that are already out there.</p>
<p><em>Happy Coding!</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Quiz App using NextJS, Chakra UI, and Firebase ]]>
                </title>
                <description>
                    <![CDATA[ Hello, everyone! Welcome to this hands-on tutorial. Before we begin you should be familiar with the basics of ReactJS, NextJS, and Firebase. If you're not, I would recommend that you go through their documentation. Here's what we're going to build: ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-quizapp-using-nextjs-chakra-ui-and-firebase/</link>
                <guid isPermaLink="false">66d460f1c7632f8bfbf1e4b3</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Firebase ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sharvin Shah ]]>
                </dc:creator>
                <pubDate>Tue, 13 Apr 2021 16:31:50 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/04/How-to-Build-a-QuizApp-using-NextJS--Chakra-UI-and-Firebase-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hello, everyone! Welcome to this hands-on tutorial. Before we begin you should be familiar with the basics of <a target="_blank" href="https://reactjs.org/docs/getting-started.html">ReactJS</a>, <a target="_blank" href="https://nextjs.org/docs/getting-started">NextJS</a>, and <a target="_blank" href="https://firebase.google.com/docs/firestore">Firebase</a>. If you're not, I would recommend that you go through their documentation.</p>
<h2 id="heading-heres-what-were-going-to-build"><strong>Here's what we're going to build:</strong></h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/CPT2104101814-1439x736--1-.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-and-heres-the-tech-well-use">And here's the tech we'll use:</h2>
<ol>
<li><p><strong>TypeScript:</strong> provides type-safe code which helps us find bugs during build time.</p>
</li>
<li><p><strong>NextJS:</strong> a React-based framework that lets us render data on the server-side. This helps Google crawl the application and which results in SEO benefits.</p>
</li>
<li><p><strong>Chakra UI:</strong> a simple, modular, and accessible component library that will give us the building blocks that we need to build the application.</p>
</li>
<li><p><strong>Firebase:</strong> provides Firestore and authentication that we are going to use in our application. We will use Firestore to save a quiz, the user-info, and answers. We'll use authentication to provide the Google SignIn feature to the user.</p>
</li>
<li><p><strong>Vercel:</strong> will host our application. It scales well, all without any configuration, and deployment is instant.</p>
</li>
<li><p><strong>Formik:</strong> provides us various components to build forms. It is hard to develop forms without formik.</p>
</li>
<li><p><strong>Yup:</strong> A form always needs to be validated. Yup is a library which we will be using for this purpose. Yup and Formik work together very well, and not much configuration is required.</p>
</li>
</ol>
<p>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 it is available in this <a target="_blank" href="https://github.com/Sharvin26/quizApp">repository</a>.</p>
<h2 id="heading-contents">Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-auth-and-user-collection">How to Set Up Auth and User Collection</a>.</p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-add-a-quiz-and-display-multiple-quizzes">How to Add a Quiz and Display Multiple Quizzes</a>.</p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-show-a-single-quiz-how-to-answer-a-quiz-and-how-to-validate-the-answer">How to Show a Single Quiz, How to Answer a Quiz and How to Validate the Answer</a>.</p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-deploy-the-app-to-vercel-and-firebase-authentication-configuration">How to Deploy the App to Vercel and Firebase Authentication Configuration</a>.</p>
</li>
</ol>
<p>Let's get started.</p>
<h2 id="heading-how-to-set-up-auth-and-user-collection"><strong>How to Set Up Auth and User Collection</strong></h2>
<p>In this section following we'll implement the following functionality:</p>
<ol>
<li><p>How to configure NextJS and Chakra UI in our quiz app.</p>
</li>
<li><p>How to configure Firebase Authentication and Firestore.</p>
</li>
<li><p>How to set up Navbar, Signup and Sign-out mechanisms.</p>
</li>
</ol>
<p>You can find the <strong>quiz app code</strong> implemented in this section at this <a target="_blank" href="https://github.com/Sharvin26/QuizApp/tree/11273c2f2ac33607e258c837c69f2473f4910656">commit</a>.</p>
<h3 id="heading-how-to-configure-nextjs-and-chakra-ui-in-our-quiz-app">How to configure NextJS and Chakra UI in our quiz app:</h3>
<p>To create a NextJS application you need to use the following command:</p>
<pre><code class="lang-shell">npx create-next-app quizapp
</code></pre>
<p>You'll get the following directory structure:</p>
<pre><code class="lang-shell">+-- node_modules
+-- pages
+-- public
+-- styles
+-- .gitignore
+-- package-lock.json
+-- package.json
+-- README.md
</code></pre>
<p><strong>Note:</strong> I am using NextJS version 10.1.3 and React version 17.0.2. You can confirm the version in your package.json.</p>
<p>Now let's convert our codebase into TypeScript-compatible code.</p>
<p>In the root directory of the project, create a file named <code>tsconfig.json</code> using the following command:</p>
<pre><code class="lang-shell">touch tsconfig.json
</code></pre>
<p>After that, install the TypeScript dependencies inside the project using the following command:</p>
<pre><code class="lang-shell">npm install --save-dev typescript @types/react @types/node
</code></pre>
<p>After that, convert the following files like this:</p>
<pre><code class="lang-shell">pages/_app.js =&gt; pages/_app.tsx
pages/index.js =&gt; pages/index.tsx
</code></pre>
<p>Remove the <code>pages/api</code> directory. Now go to the <code>pages/_app.tsx</code> and replace the full code as follows:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { AppProps } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/app'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params">{ Component, pageProps }: AppProps</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...pageProps</span>} /&gt;</span></span>
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<p>Go to <code>pages/index.tsx</code> and replace it with the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">'next/head'</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">Home</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">Head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>QuizApp<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <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">"/favicon.ico"</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">main</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">footer</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Now start the development server using the following command:</p>
<pre><code class="lang-shell">npm run dev
</code></pre>
<p>The first time when you start the development server, Next will:</p>
<ol>
<li><p>Populate the <code>tsconfig.json</code> file for you.</p>
</li>
<li><p>Create the <code>next-env.d.ts</code> file, which ensures that Next types are picked up by the TypeScript compiler. You should <strong>not</strong> touch this file.</p>
</li>
</ol>
<p>Delete the <code>styles</code> directory from the root directory.</p>
<p>After following the above steps you'll have the following directory structure:</p>
<pre><code class="lang-shell">+-- node_modules
+-- pages
|   +-- _app.tsx
|   +-- index.tsx
+-- public
+-- .gitignore
+-- package-lock.json
+-- package.json
+-- README.md
+-- tsconfig.json
</code></pre>
<p>Now go to <code>http://localhost:3000</code> and you'll find an empty screen.</p>
<p>Let's install Chakra UI using the following command:</p>
<pre><code class="lang-shell">npm i @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^4
</code></pre>
<p><strong>Note:</strong> If you use zsh you'll need to add the escape character () after @ as follows:</p>
<pre><code class="lang-shell">npm i @chakra-ui/react @emotion/react@\^11 @emotion/styled@\^11 framer-motion@\^4
</code></pre>
<p>As per chakra documentation, we need to wrap <code>&lt;Component /&gt;</code> with <code>ChakraProvider</code> in the <code>pages/_app.tsx</code> as follows:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { ChakraProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;
<span class="hljs-keyword">import</span> { AppProps } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/app'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params">{ Component, pageProps }: AppProps</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ChakraProvider</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...pageProps</span>} /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ChakraProvider</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Basically, this will perform CSSReset and pass the <a target="_blank" href="https://chakra-ui.com/docs/theming/theme">chakra theme</a> to the component.</p>
<p>Now we will create our <code>Navbar</code> component.</p>
<p>To create this component first we need to create a directory named <code>src</code> in the root directory and cut/paste the <code>pages</code> directory inside the <code>src</code> directory.</p>
<p>After that create a directory named <code>common</code> under the <code>src</code> directory.</p>
<p>Under the <code>common</code> directory create a file named <code>Navbar.tsx</code>. Copy/paste the following code inside that file:</p>
<pre><code class="lang-jsx"><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> { Box, Divider, Flex, Heading, Link } <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/router'</span>;

<span class="hljs-keyword">const</span> Navbar: React.FC&lt;{}&gt; = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> router = useRouter();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Flex</span> <span class="hljs-attr">justify</span>=<span class="hljs-string">"space-between"</span> <span class="hljs-attr">m</span>=<span class="hljs-string">{4}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> router.push('/')} as="button"&gt;
          QuizApp
        <span class="hljs-tag">&lt;/<span class="hljs-name">Heading</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Box</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">p</span>=<span class="hljs-string">{2}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
              <span class="hljs-attr">p</span>=<span class="hljs-string">{2}</span>
              <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> router.push('/signin')}
              fontWeight={
                router.pathname === '/signin' ? 'extrabold' : 'normal'
              }
            &gt;
              Sign In
            <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Flex</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Divider</span>
        <span class="hljs-attr">css</span>=<span class="hljs-string">{{</span>
          <span class="hljs-attr">boxShadow:</span> '<span class="hljs-attr">1px</span> <span class="hljs-attr">1px</span> #<span class="hljs-attr">888888</span>',
        }}
      /&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Navbar;
</code></pre>
<p>After that go to <code>pages/index.tsx</code> and add the following line between the <code>&lt;main&gt;&lt;/main&gt;</code> tag.</p>
<pre><code class="lang-jsx">&lt;Navbar /&gt;
</code></pre>
<p>You'll also need to import the Navbar using the following syntax:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">'../common/Navbar'</span>;
</code></pre>
<p>Go to your web browser and open <code>http://localhost:3000</code> and you'll see the following output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-04-at-7.26.21-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-configure-firebase-authentication-and-firestore">How to Configure Firebase Authentication and Firestore:</h3>
<p>Now let's configure Firebase. Go to the <a target="_blank" href="https://console.firebase.google.com/u/0/">firebase console</a>. Click on Add project:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-04-at-7.27.47-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>After that add your project name as follows:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-04-at-7.29.36-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Next, it will ask if you want to enable Google Analytics or not. I prefer to disable it, but you can switch it on if you want.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-04-at-7.29.51-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now click on <strong>Create project</strong>. It will take some time to create the project.</p>
<p>Once the project is created you'll see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-04-at-7.31.16-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>After clicking on continue you'll see a dashboard that looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-04-at-7.34.05-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click on the <strong>Settings &gt; Project Settings &gt; General</strong>. Inside the General tab scroll down and in the <strong>Your apps</strong> card, select the third option (after the Android icon).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-04-at-7.35.40-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>It will ask for some details to register the app. Add your app's nickname as follows:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-04-at-7.37.27-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>After you've clicked on <strong>register app</strong>, Firebase will give you a snippet. Copy-paste these details into a file and then you can click on <strong>continue to console</strong>.</p>
<p>Now go to the <strong>service accounts tab</strong> in project settings and click on the button <strong>Generate new private key</strong>. It will download some configurations that we will need for firebase-admin.</p>
<p>Now go back and click on the Authentication tab:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-04-at-8.14.42-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>After that click on the <strong>Get started</strong> button and you'll get the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-04-at-8.15.45-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now click on Google text and click the <strong>Enable</strong> button:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-04-at-8.16.22-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Select the project configured email as your email id.</p>
<p>Click on the Firestore tab and click on Create database button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-04-at-8.19.05-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Once you've clicked on Create database it will ask for the mode. Select test mode for developing the application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-04-at-8.19.37-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click on Next. It will ask for the location. Select the appropriate option and then click the Enable button.</p>
<h3 id="heading-how-to-set-up-the-navbar-signup-and-sign-out-mechanisms">How to set up the Navbar, Signup, and Sign-out mechanisms:</h3>
<p>Now back to our project. Install the following dependencies using this npm command:</p>
<pre><code class="lang-shell">npm i firebase firebase-admin
</code></pre>
<p>Create a directory named <code>lib</code> inside the <code>src</code> directory.</p>
<p>In the <code>lib</code> directory create two files named <code>firebase.ts</code> and <code>firebase-admin.ts</code>.</p>
<p>Copy the following code inside <code>firebase.ts</code>:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> firebase <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase/app'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'firebase/firestore'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'firebase/auth'</span>;

<span class="hljs-keyword">const</span> firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
};

<span class="hljs-keyword">try</span> {
  firebase.initializeApp(firebaseConfig);
} <span class="hljs-keyword">catch</span> (err) {
  <span class="hljs-keyword">if</span> (!<span class="hljs-regexp">/already exists/</span>.test(err.message)) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Firebase initialization error'</span>, err.stack);
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> firebase;
</code></pre>
<p>Here we initialize the Firebase library using <code>apikey</code>, <code>authdomain</code> and <code>projectId</code>.</p>
<p>Paste the following code inside <code>firebase-admin.ts</code>:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> admin <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase-admin'</span>;

<span class="hljs-keyword">if</span> (!admin.apps.length) {
  admin.initializeApp({
    credential: admin.credential.cert({
      projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
      privateKey: process.env.FIREBASE_PRIVATE_KEY,
      clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
    }),
    databaseURL: process.env.FIREBASE_DATABASE_URL,
  });
}

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

<span class="hljs-keyword">export</span> { db, auth };
</code></pre>
<p>Here we initialize the <code>firebase-admin</code> library using <code>projectId</code>, <code>privateKey</code>, <code>clientEmail</code>, and <code>databaseURL</code>.</p>
<p>Now in the root directory create a file named <code>.env.local</code> and paste in the following code:</p>
<pre><code class="lang-python">NEXT_PUBLIC_FIREBASE_API_KEY=
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=
NEXT_PUBLIC_FIREBASE_PROJECT_ID=

FIREBASE_PRIVATE_KEY=
FIREBASE_CLIENT_EMAIL=
FIREBASE_DATABASE_URL=
</code></pre>
<p>You'll find <code>NEXT_PUBLIC_FIREBASE_API_KEY</code>, <code>NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN</code>, <code>NEXT_PUBLIC_FIREBASE_PROJECT_ID</code> inside the <strong>Firebase Console</strong> &gt; <strong>Settings &gt; Project Settings &gt; General &gt; Your Apps Card</strong>.</p>
<p>You'll find <code>FIREBASE_PRIVATE_KEY</code>, <code>FIREBASE_CLIENT_EMAIL</code> under the service account tab. We can generate a new private key using the <strong>Generate new private key</strong> button. That file contains both sets of data.</p>
<p>For the <code>FIREBASE_DATABASE_URL</code> add <code>https://&lt;database-name&gt;.firebaseio.com</code>. Replace <code>database-name</code> with your database name.</p>
<p><strong>Note:</strong> You can find the <code>database-name</code> under <strong>firebase console &gt; firestore</strong> in the data tab (refer to the screen shot below).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-11-at-4.47.36-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now in the <code>lib</code> directory create a third file named <code>auth.tsx</code>. This is going to contain our Authorization mechanism and state. Paste the following code in this file:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { Context, createContext, useContext, useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { addUser } <span class="hljs-keyword">from</span> <span class="hljs-string">'../utils/db'</span>;
<span class="hljs-keyword">import</span> firebase <span class="hljs-keyword">from</span> <span class="hljs-string">'./firebase'</span>;

<span class="hljs-keyword">interface</span> Auth {
  uid: <span class="hljs-built_in">string</span>;
  email: <span class="hljs-built_in">string</span> | <span class="hljs-literal">null</span>;
  name: <span class="hljs-built_in">string</span> | <span class="hljs-literal">null</span>;
  photoUrl: <span class="hljs-built_in">string</span> | <span class="hljs-literal">null</span>;
  token: <span class="hljs-built_in">string</span> | <span class="hljs-literal">null</span>;
}

<span class="hljs-keyword">interface</span> AuthContext {
  auth: Auth | <span class="hljs-literal">null</span>;
  loading: <span class="hljs-built_in">boolean</span>;
  siginWithGoogle: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt;;
  signOut: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt;;
}

<span class="hljs-keyword">const</span> authContext: Context&lt;AuthContext&gt; = createContext&lt;AuthContext&gt;({
  auth: <span class="hljs-literal">null</span>,
  loading: <span class="hljs-literal">true</span>,
  siginWithGoogle: <span class="hljs-keyword">async</span> () =&gt; {},
  signOut: <span class="hljs-keyword">async</span> () =&gt; {},
});

<span class="hljs-keyword">const</span> formatAuthState = (user: firebase.User): <span class="hljs-function"><span class="hljs-params">Auth</span> =&gt;</span> ({
  uid: user.uid,
  email: user.email,
  name: user.displayName,
  photoUrl: user.photoURL,
  token: <span class="hljs-literal">null</span>,
});

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useProvideAuth</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [auth, setAuth] = useState&lt;Auth | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState&lt;<span class="hljs-built_in">boolean</span>&gt;(<span class="hljs-literal">true</span>);

  <span class="hljs-keyword">const</span> handleAuthChange = <span class="hljs-keyword">async</span> (authState: firebase.User | <span class="hljs-literal">null</span>) =&gt; {
    <span class="hljs-keyword">if</span> (!authState) {
      setLoading(<span class="hljs-literal">false</span>);
      <span class="hljs-keyword">return</span>;
    }
    <span class="hljs-keyword">const</span> formattedAuth = formatAuthState(authState);
    formattedAuth.token = <span class="hljs-keyword">await</span> authState.getIdToken();
    setAuth(formattedAuth);
    setLoading(<span class="hljs-literal">false</span>);
  };

  <span class="hljs-keyword">const</span> signedIn = <span class="hljs-keyword">async</span> (
    response: firebase.auth.UserCredential,
    provider: <span class="hljs-built_in">String</span> = <span class="hljs-string">'google'</span>
  ) =&gt; {
    <span class="hljs-keyword">if</span> (!response.user) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'No User'</span>);
    }
    <span class="hljs-keyword">const</span> authUser = formatAuthState(response.user);
    <span class="hljs-keyword">await</span> addUser({ ...authUser, provider });
  };

  <span class="hljs-keyword">const</span> clear = <span class="hljs-function">() =&gt;</span> {
    setAuth(<span class="hljs-literal">null</span>);
    setLoading(<span class="hljs-literal">true</span>);
  };

  <span class="hljs-keyword">const</span> siginWithGoogle = <span class="hljs-keyword">async</span> () =&gt; {
    setLoading(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">return</span> firebase
      .auth()
      .signInWithPopup(<span class="hljs-keyword">new</span> firebase.auth.GoogleAuthProvider())
      .then(signedIn);
  };
  <span class="hljs-keyword">const</span> signOut = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">return</span> firebase.auth().signOut().then(clear);
  };

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> unsubscribe = firebase.auth().onAuthStateChanged(handleAuthChange);
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> unsubscribe();
  }, []);

  <span class="hljs-keyword">return</span> {
    auth,
    loading,
    siginWithGoogle,
    signOut,
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AuthProvider</span>(<span class="hljs-params">{ children }: <span class="hljs-built_in">any</span></span>) </span>{
  <span class="hljs-keyword">const</span> auth = useProvideAuth();
  <span class="hljs-keyword">return</span> &lt;authContext.Provider value={auth}&gt;{children}&lt;/authContext.Provider&gt;;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useAuth = <span class="hljs-function">() =&gt;</span> useContext(authContext);
</code></pre>
<p>In the <code>src</code> directory create a folder named <code>utils</code> and under that folder create a file named <code>db.ts</code>. Add the following code inside that file:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> firebase <span class="hljs-keyword">from</span> <span class="hljs-string">'../lib/firebase'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addUser = <span class="hljs-keyword">async</span> (authUser: <span class="hljs-built_in">any</span>) =&gt; {
  <span class="hljs-keyword">const</span> resp = <span class="hljs-keyword">await</span> firebase
    .firestore()
    .collection(<span class="hljs-string">'users'</span>)
    .doc(authUser.uid <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>)
    .set({ ...authUser }, { merge: <span class="hljs-literal">true</span> });
  <span class="hljs-keyword">return</span> resp;
};
</code></pre>
<p>Go to the <code>Navbar.tsx</code> under component directory and update the previous code with the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Box, Divider, Flex, Heading, Link } <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/router'</span>;
<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> { useAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">'../lib/auth'</span>;

<span class="hljs-keyword">const</span> Navbar: React.FC&lt;{}&gt; = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { auth, signOut } = useAuth();
  <span class="hljs-keyword">const</span> router = useRouter();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Flex</span> <span class="hljs-attr">justify</span>=<span class="hljs-string">"space-between"</span> <span class="hljs-attr">m</span>=<span class="hljs-string">{4}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> router.push('/')} as="button"&gt;
          QuizApp
        <span class="hljs-tag">&lt;/<span class="hljs-name">Heading</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Box</span>&gt;</span>
          {auth ? (
            <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">p</span>=<span class="hljs-string">{2}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">p</span>=<span class="hljs-string">{2}</span>
                <span class="hljs-attr">fontWeight</span>=<span class="hljs-string">{</span>
                  <span class="hljs-attr">router.pathname</span> === <span class="hljs-string">'/quiz/new'</span> ? '<span class="hljs-attr">extrabold</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">normal</span>'
                }
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> router.push('/quiz/new')}
              &gt;
                Add new quiz
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">p</span>=<span class="hljs-string">{2}</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> signOut()}&gt;
                Logout
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
          ) : (
            <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">p</span>=<span class="hljs-string">{2}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">p</span>=<span class="hljs-string">{2}</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> router.push('/signin')}
                fontWeight={
                  router.pathname === '/signin' ? 'extrabold' : 'normal'
                }
              &gt;
                Sign In
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
          )}
        <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Flex</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Divider</span>
        <span class="hljs-attr">css</span>=<span class="hljs-string">{{</span>
          <span class="hljs-attr">boxShadow:</span> '<span class="hljs-attr">1px</span> <span class="hljs-attr">1px</span> #<span class="hljs-attr">888888</span>',
        }}
      /&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Navbar;
</code></pre>
<p>Replace the <code>_app.tsx</code> with the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { ChakraProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;
<span class="hljs-keyword">import</span> { AppProps } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/app'</span>;
<span class="hljs-keyword">import</span> { AuthProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'../lib/auth'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params">{ Component, pageProps }: AppProps</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ChakraProvider</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">AuthProvider</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...pageProps</span>} /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">AuthProvider</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ChakraProvider</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Create a new file named <code>signin.tsx</code> under the pages directory and add the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Button, Center, Container, Heading, VStack } <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/router'</span>;
<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> { FcGoogle } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-icons/fc'</span>;
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">'../common/Navbar'</span>;
<span class="hljs-keyword">import</span> { useAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">'../lib/auth'</span>;

<span class="hljs-keyword">const</span> signin = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { auth, siginWithGoogle } = useAuth();
  <span class="hljs-keyword">const</span> router = useRouter();

  <span class="hljs-keyword">if</span> (auth) {
    router.push((router.query.next <span class="hljs-keyword">as</span> string) || <span class="hljs-string">'/'</span>);
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Container</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Center</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{10}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">VStack</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">"4"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">fontSize</span>=<span class="hljs-string">"3xl"</span> <span class="hljs-attr">mb</span>=<span class="hljs-string">{2}</span>&gt;</span>
              Hello, Welcome to the Quiz App!!
            <span class="hljs-tag">&lt;/<span class="hljs-name">Heading</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">leftIcon</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">FcGoogle</span> /&gt;</span>} onClick={() =&gt; siginWithGoogle()}&gt;
              Sign In with Google
            <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">VStack</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">Container</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> signin;
</code></pre>
<p>You'll need to install react-icons. To install react-icons use the following command:</p>
<pre><code class="lang-shell">npm i react-icons
</code></pre>
<p>Now restart the development server and go to the <code>http://localhost:3000</code>. Click on the Sign In link and you'll get the following screen.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-04-at-8.12.39-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now click the Sign in with Google Button. After a successful sign-in, you will be redirected to the Home page.</p>
<h2 id="heading-how-to-add-a-quiz-and-display-multiple-quizzes"><strong>How to Add a Quiz and Display Multiple Quizzes</strong></h2>
<p>In this section we'll implement the following functionality:</p>
<ol>
<li><p>How to set up the Add a Quiz mechanism.</p>
</li>
<li><p>How to set up the Display Multiple Quizzes mechanism.</p>
</li>
</ol>
<p>You can find the <strong>quiz app code</strong> in this section at this <a target="_blank" href="https://github.com/Sharvin26/QuizApp/tree/5ff954a606151e9574ac747ae3780d7644561865">commit</a>.</p>
<h3 id="heading-how-to-set-up-the-add-a-quiz-mechanism">How to set up the Add a Quiz mechanism:</h3>
<p>Now we will focus on adding the quiz. To add a new quiz we will use <strong>Formik.</strong> It will help us configure the dynamic form and <strong>Yup</strong> will help us with the validation of those forms.</p>
<p>Let's install both the libraries using the following command.</p>
<pre><code class="lang-shell">npm i formik yup
</code></pre>
<p>We will also use a package named <strong>uuid</strong> to give a unique identifier to our questions and options. To install the package use the following command:</p>
<pre><code class="lang-shell">npm i uuid
</code></pre>
<p>We will also need chakra icons so install them using the following command:</p>
<pre><code class="lang-shell">npm i @chakra-ui/icons
</code></pre>
<p>We will need Axios to make an API call to our Next serverless environment. Use the following command to install it:</p>
<pre><code class="lang-shell">npm i axios
</code></pre>
<p>Inside the <strong>src &gt; pages</strong> directory create a new directory named <strong>quiz</strong> and under that directory create a new directory named <strong>new</strong>.</p>
<p>Inside the <strong>new</strong> directory create a file named <code>index.tsx</code> and paste the following code into it:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { AddIcon, MinusIcon } <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/icons'</span>;
<span class="hljs-keyword">import</span> {
  Box,
  Button,
  Center,
  Container,
  Divider,
  Flex,
  FormControl,
  FormErrorMessage,
  FormLabel,
  IconButton,
  Input,
  SimpleGrid,
  Text,
  Textarea,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;
<span class="hljs-keyword">import</span> { Field, FieldArray, Form, Formik, getIn } <span class="hljs-keyword">from</span> <span class="hljs-string">'formik'</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/router'</span>;
<span class="hljs-keyword">import</span> React, { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { v4 <span class="hljs-keyword">as</span> uuidv4 } <span class="hljs-keyword">from</span> <span class="hljs-string">'uuid'</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> yup <span class="hljs-keyword">from</span> <span class="hljs-string">'yup'</span>;
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../common/Navbar'</span>;
<span class="hljs-keyword">import</span> { useAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../lib/auth'</span>;
<span class="hljs-keyword">import</span> { addQuizApi } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../utils/service'</span>;

<span class="hljs-keyword">const</span> optionData = [
  {
    <span class="hljs-attr">label</span>: <span class="hljs-string">'Option A:'</span>,
  },
  {
    <span class="hljs-attr">label</span>: <span class="hljs-string">'Option B:'</span>,
  },
  {
    <span class="hljs-attr">label</span>: <span class="hljs-string">'Option C:'</span>,
  },
  {
    <span class="hljs-attr">label</span>: <span class="hljs-string">'Option D:'</span>,
  },
];

<span class="hljs-keyword">const</span> answerOption = [
  {
    <span class="hljs-attr">label</span>: <span class="hljs-string">'A'</span>,
    <span class="hljs-attr">answer</span>: <span class="hljs-number">0</span>,
  },
  {
    <span class="hljs-attr">label</span>: <span class="hljs-string">'B'</span>,
    <span class="hljs-attr">answer</span>: <span class="hljs-number">1</span>,
  },
  {
    <span class="hljs-attr">label</span>: <span class="hljs-string">'C'</span>,
    <span class="hljs-attr">answer</span>: <span class="hljs-number">2</span>,
  },
  {
    <span class="hljs-attr">label</span>: <span class="hljs-string">'D'</span>,
    <span class="hljs-attr">answer</span>: <span class="hljs-number">3</span>,
  },
];

<span class="hljs-keyword">const</span> Index = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { auth, loading } = useAuth();

  <span class="hljs-keyword">const</span> router = useRouter();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (!auth &amp;&amp; !loading) {
      router.push(<span class="hljs-string">'/signin?next=/quiz/new'</span>);
    }
  }, [auth, loading]);

  <span class="hljs-keyword">const</span> questionsData = {
    <span class="hljs-attr">title</span>: <span class="hljs-string">''</span>,
    <span class="hljs-attr">options</span>: [{ <span class="hljs-attr">title</span>: <span class="hljs-string">''</span> }, { <span class="hljs-attr">title</span>: <span class="hljs-string">''</span> }, { <span class="hljs-attr">title</span>: <span class="hljs-string">''</span> }, { <span class="hljs-attr">title</span>: <span class="hljs-string">''</span> }],
    <span class="hljs-attr">answer</span>: <span class="hljs-string">'0'</span>,
  };

  <span class="hljs-keyword">const</span> initialValues = {
    <span class="hljs-attr">title</span>: <span class="hljs-string">''</span>,
    <span class="hljs-attr">description</span>: <span class="hljs-string">''</span>,
    <span class="hljs-attr">questions</span>: [questionsData],
  };

  <span class="hljs-keyword">const</span> validationSchema = yup.object().shape({
    <span class="hljs-attr">title</span>: yup.string().required(<span class="hljs-string">'Required'</span>),
    <span class="hljs-attr">description</span>: yup.string().required(<span class="hljs-string">'Required'</span>),
    <span class="hljs-attr">questions</span>: yup
      .array()
      .of(
        yup.object().shape({
          <span class="hljs-attr">title</span>: yup.string().required(<span class="hljs-string">'Required!'</span>),
          <span class="hljs-attr">options</span>: yup.array().of(
            yup.object().shape({
              <span class="hljs-attr">title</span>: yup.string().required(<span class="hljs-string">'Required!'</span>),
            })
          ),
        })
      )
      .required(<span class="hljs-string">'Must add a question'</span>),
  });

  <span class="hljs-keyword">const</span> submitHandler = <span class="hljs-keyword">async</span> (values, actions) =&gt; {
    <span class="hljs-keyword">try</span> {
      values = {
        ...values,
        <span class="hljs-attr">createdAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
        <span class="hljs-attr">updatedAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
        <span class="hljs-attr">questions</span>: values.questions.map(<span class="hljs-function">(<span class="hljs-params">question</span>) =&gt;</span> {
          <span class="hljs-keyword">return</span> {
            ...question,
            <span class="hljs-attr">options</span>: question.options.map(<span class="hljs-function">(<span class="hljs-params">option</span>) =&gt;</span> {
              <span class="hljs-keyword">return</span> { ...option, <span class="hljs-attr">optionId</span>: uuidv4() };
            }),
            <span class="hljs-attr">questionId</span>: uuidv4(),
          };
        }),
      };
      <span class="hljs-keyword">await</span> addQuizApi(auth, values);
      router.push(<span class="hljs-string">'/'</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'error'</span>, error);
    } <span class="hljs-keyword">finally</span> {
      actions.setSubmitting(<span class="hljs-literal">false</span>);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Container</span>
        <span class="hljs-attr">maxW</span>=<span class="hljs-string">"3xl"</span>
        <span class="hljs-attr">mt</span>=<span class="hljs-string">{5}</span>
        <span class="hljs-attr">mb</span>=<span class="hljs-string">{5}</span>
        <span class="hljs-attr">borderWidth</span>=<span class="hljs-string">"1px"</span>
        <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"lg"</span>
        <span class="hljs-attr">p</span>=<span class="hljs-string">{6}</span>
        <span class="hljs-attr">boxShadow</span>=<span class="hljs-string">"xl"</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Formik</span>
          <span class="hljs-attr">initialValues</span>=<span class="hljs-string">{initialValues}</span>
          <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{submitHandler}</span>
          <span class="hljs-attr">validationSchema</span>=<span class="hljs-string">{validationSchema}</span>
        &gt;</span>
          {(props) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">Form</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Field</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span>&gt;</span>
                {({ field, form }) =&gt; (
                  <span class="hljs-tag">&lt;<span class="hljs-name">FormControl</span>
                    <span class="hljs-attr">isInvalid</span>=<span class="hljs-string">{form.errors.title</span> &amp;&amp; <span class="hljs-attr">form.touched.title</span>}
                  &gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">fontSize</span>=<span class="hljs-string">"xl"</span>&gt;</span>
                      Quiz Title
                    <span class="hljs-tag">&lt;/<span class="hljs-name">FormLabel</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Input</span> {<span class="hljs-attr">...field</span>} <span class="hljs-attr">id</span>=<span class="hljs-string">"title"</span> /&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">FormErrorMessage</span>&gt;</span>{form.errors.title}<span class="hljs-tag">&lt;/<span class="hljs-name">FormErrorMessage</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">FormControl</span>&gt;</span>
                )}
              <span class="hljs-tag">&lt;/<span class="hljs-name">Field</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Field</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>&gt;</span>
                {({ field, form }) =&gt; (
                  <span class="hljs-tag">&lt;<span class="hljs-name">FormControl</span>
                    <span class="hljs-attr">isInvalid</span>=<span class="hljs-string">{</span>
                      <span class="hljs-attr">form.errors.description</span> &amp;&amp; <span class="hljs-attr">form.touched.description</span>
                    }
                  &gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">fontSize</span>=<span class="hljs-string">"xl"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{4}</span>&gt;</span>
                      Quiz description
                    <span class="hljs-tag">&lt;/<span class="hljs-name">FormLabel</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Textarea</span> {<span class="hljs-attr">...field</span>} <span class="hljs-attr">id</span>=<span class="hljs-string">"description"</span> /&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">FormErrorMessage</span>&gt;</span>
                      {form.errors.description}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">FormErrorMessage</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">FormControl</span>&gt;</span>
                )}
              <span class="hljs-tag">&lt;/<span class="hljs-name">Field</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Field</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"questions"</span>&gt;</span>
                {({ field }) =&gt; (
                  <span class="hljs-tag">&lt;<span class="hljs-name">FormControl</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"questions"</span> <span class="hljs-attr">fontSize</span>=<span class="hljs-string">"xl"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{4}</span>&gt;</span>
                      Enter your question data:
                    <span class="hljs-tag">&lt;/<span class="hljs-name">FormLabel</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">ml</span>=<span class="hljs-string">{4}</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">FieldArray</span> {<span class="hljs-attr">...field</span>} <span class="hljs-attr">name</span>=<span class="hljs-string">"questions"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"questions"</span>&gt;</span>
                        {(fieldArrayProps) =&gt; {
                          const { push, remove, form } = fieldArrayProps;
                          const { values, errors, touched } = form;
                          const { questions } = values;
                          const errorHandler = (name) =&gt; {
                            const error = getIn(errors, name);
                            const touch = getIn(touched, name);
                            return touch &amp;&amp; error ? error : null;
                          };
                          return (
                            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                              {questions.map((_question, index) =&gt; {
                                return (
                                  <span class="hljs-tag">&lt;<span class="hljs-name">Flex</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">direction</span>=<span class="hljs-string">"column"</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">FormControl</span>
                                      <span class="hljs-attr">isInvalid</span>=<span class="hljs-string">{errorHandler(</span>
                                        `<span class="hljs-attr">questions</span>[${<span class="hljs-attr">index</span>}][<span class="hljs-attr">title</span>]`
                                      )}
                                    &gt;</span>
                                      <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span>
                                        <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">questions</span>[${<span class="hljs-attr">index</span>}][<span class="hljs-attr">title</span>]`}
                                      &gt;</span>
                                        Question Title:
                                      <span class="hljs-tag">&lt;/<span class="hljs-name">FormLabel</span>&gt;</span>
                                      <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                                        <span class="hljs-attr">name</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">questions</span>[${<span class="hljs-attr">index</span>}][<span class="hljs-attr">title</span>]`}
                                        <span class="hljs-attr">as</span>=<span class="hljs-string">{Field}</span>
                                        <span class="hljs-attr">mb</span>=<span class="hljs-string">{</span>
                                          !<span class="hljs-attr">errorHandler</span>(
                                            `<span class="hljs-attr">questions</span>[${<span class="hljs-attr">index</span>}][<span class="hljs-attr">title</span>]`
                                          ) &amp;&amp; <span class="hljs-attr">3</span>
                                        }
                                      /&gt;</span>
                                      <span class="hljs-tag">&lt;<span class="hljs-name">FormErrorMessage</span>&gt;</span>
                                        {errorHandler(
                                          `questions[${index}][title]`
                                        )}
                                      <span class="hljs-tag">&lt;/<span class="hljs-name">FormErrorMessage</span>&gt;</span>
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">FormControl</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">SimpleGrid</span>
                                      <span class="hljs-attr">minChildWidth</span>=<span class="hljs-string">"300px"</span>
                                      <span class="hljs-attr">spacing</span>=<span class="hljs-string">"10px"</span>
                                      <span class="hljs-attr">mb</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">base:</span> <span class="hljs-attr">4</span> }}
                                    &gt;</span>
                                      {optionData.map((option, subIndex) =&gt; (
                                        <span class="hljs-tag">&lt;<span class="hljs-name">FormControl</span>
                                          <span class="hljs-attr">mb</span>=<span class="hljs-string">{2}</span>
                                          <span class="hljs-attr">key</span>=<span class="hljs-string">{subIndex}</span>
                                          <span class="hljs-attr">isInvalid</span>=<span class="hljs-string">{errorHandler(</span>
                                            `<span class="hljs-attr">questions</span>[${<span class="hljs-attr">index</span>}][<span class="hljs-attr">options</span>][${<span class="hljs-attr">subIndex</span>}]<span class="hljs-attr">.title</span>`
                                          )}
                                        &gt;</span>
                                          <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span>
                                            <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">questions</span>[${<span class="hljs-attr">index</span>}][<span class="hljs-attr">options</span>][${<span class="hljs-attr">subIndex</span>}]<span class="hljs-attr">.title</span>`}
                                          &gt;</span>
                                            {option.label}
                                          <span class="hljs-tag">&lt;/<span class="hljs-name">FormLabel</span>&gt;</span>
                                          <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                                            <span class="hljs-attr">name</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">questions</span>[${<span class="hljs-attr">index</span>}][<span class="hljs-attr">options</span>][${<span class="hljs-attr">subIndex</span>}]<span class="hljs-attr">.title</span>`}
                                            <span class="hljs-attr">as</span>=<span class="hljs-string">{Field}</span>
                                          /&gt;</span>
                                          <span class="hljs-tag">&lt;<span class="hljs-name">FormErrorMessage</span>&gt;</span>
                                            {errorHandler(
                                              `questions[${index}][options][${subIndex}].title`
                                            )}
                                          <span class="hljs-tag">&lt;/<span class="hljs-name">FormErrorMessage</span>&gt;</span>
                                        <span class="hljs-tag">&lt;/<span class="hljs-name">FormControl</span>&gt;</span>
                                      ))}
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">SimpleGrid</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">Box</span>&gt;</span>
                                      <span class="hljs-tag">&lt;<span class="hljs-name">Text</span> <span class="hljs-attr">mb</span>=<span class="hljs-string">"8px"</span>&gt;</span>Correct Answer:<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
                                      <span class="hljs-tag">&lt;<span class="hljs-name">Field</span>
                                        <span class="hljs-attr">component</span>=<span class="hljs-string">"select"</span>
                                        <span class="hljs-attr">name</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">questions</span>[${<span class="hljs-attr">index</span>}][<span class="hljs-attr">answer</span>]`}
                                        <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
                                          <span class="hljs-attr">width:</span> '<span class="hljs-attr">100</span>%',
                                          <span class="hljs-attr">padding:</span> '<span class="hljs-attr">10px</span>',
                                        }}
                                      &gt;</span>
                                        {answerOption.map((value, key) =&gt; (
                                          <span class="hljs-tag">&lt;<span class="hljs-name">option</span>
                                            <span class="hljs-attr">value</span>=<span class="hljs-string">{value.answer}</span>
                                            <span class="hljs-attr">key</span>=<span class="hljs-string">{key}</span>
                                          &gt;</span>
                                            {value.label}
                                          <span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                                        ))}
                                      <span class="hljs-tag">&lt;/<span class="hljs-name">Field</span>&gt;</span>
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">Flex</span>
                                      <span class="hljs-attr">direction</span>=<span class="hljs-string">"row"</span>
                                      <span class="hljs-attr">justify</span>=<span class="hljs-string">"flex-end"</span>
                                      <span class="hljs-attr">mt</span>=<span class="hljs-string">{4}</span>
                                    &gt;</span>
                                      {index &gt; 0 &amp;&amp; (
                                        <span class="hljs-tag">&lt;<span class="hljs-name">IconButton</span>
                                          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> remove(index)}
                                          aria-label="Remove Question"
                                          icon={<span class="hljs-tag">&lt;<span class="hljs-name">MinusIcon</span> /&gt;</span>}
                                          variant="ghost"
                                        &gt;
                                          -
                                        <span class="hljs-tag">&lt;/<span class="hljs-name">IconButton</span>&gt;</span>
                                      )}
                                      {index === questions.length - 1 &amp;&amp; (
                                        <span class="hljs-tag">&lt;<span class="hljs-name">IconButton</span>
                                          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> push(questionsData)}
                                          aria-label="Add Question"
                                          icon={<span class="hljs-tag">&lt;<span class="hljs-name">AddIcon</span> /&gt;</span>}
                                          variant="ghost"
                                        &gt;
                                          +
                                        <span class="hljs-tag">&lt;/<span class="hljs-name">IconButton</span>&gt;</span>
                                      )}
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">Flex</span>&gt;</span>
                                    {index !== questions.length - 1 &amp;&amp; (
                                      <span class="hljs-tag">&lt;<span class="hljs-name">Divider</span>
                                        <span class="hljs-attr">mt</span>=<span class="hljs-string">{2}</span>
                                        <span class="hljs-attr">mb</span>=<span class="hljs-string">{4}</span>
                                        <span class="hljs-attr">css</span>=<span class="hljs-string">{{</span>
                                          <span class="hljs-attr">boxShadow:</span> '<span class="hljs-attr">1px</span> <span class="hljs-attr">1px</span> #<span class="hljs-attr">888888</span>',
                                        }}
                                      /&gt;</span>
                                    )}
                                  <span class="hljs-tag">&lt;/<span class="hljs-name">Flex</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">FieldArray</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">FormControl</span>&gt;</span>
                )}
              <span class="hljs-tag">&lt;/<span class="hljs-name">Field</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">Button</span>
                  <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"green"</span>
                  <span class="hljs-attr">isLoading</span>=<span class="hljs-string">{props.isSubmitting}</span>
                  <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
                  <span class="hljs-attr">disabled</span>=<span class="hljs-string">{!(props.isValid</span> &amp;&amp; <span class="hljs-attr">props.dirty</span>)}
                &gt;</span>
                  Submit Quiz
                <span class="hljs-tag">&lt;/<span class="hljs-name">Button</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">Form</span>&gt;</span>
          )}
        <span class="hljs-tag">&lt;/<span class="hljs-name">Formik</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Index;
</code></pre>
<p>Let's understand the code above.</p>
<p><strong>Note:</strong> Don't copy/paste the individual code snippets below. I took pieces from the big code block above and broke them into smaller chunks so we can understand what's going on.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> questionsData = {
  <span class="hljs-attr">title</span>: <span class="hljs-string">''</span>,
  <span class="hljs-attr">options</span>: [{ <span class="hljs-attr">title</span>: <span class="hljs-string">''</span> }, { <span class="hljs-attr">title</span>: <span class="hljs-string">''</span> }, { <span class="hljs-attr">title</span>: <span class="hljs-string">''</span> }, { <span class="hljs-attr">title</span>: <span class="hljs-string">''</span> }],
  <span class="hljs-attr">answer</span>: <span class="hljs-string">'0'</span>,
};

<span class="hljs-keyword">const</span> initialValues = {
  <span class="hljs-attr">title</span>: <span class="hljs-string">''</span>,
  <span class="hljs-attr">description</span>: <span class="hljs-string">''</span>,
  <span class="hljs-attr">questions</span>: [questionsData],
};

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Formik</span>
   <span class="hljs-attr">initialValues</span>=<span class="hljs-string">{initialValues}</span>
   <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{submitHandler}</span>
   <span class="hljs-attr">validationSchema</span>=<span class="hljs-string">{validationSchema}</span>
&gt;</span>
    {(props) =&gt; (
       <span class="hljs-tag">&lt;<span class="hljs-name">Form</span>&gt;</span>
         #Input field and button
       <span class="hljs-tag">&lt;/<span class="hljs-name">Form</span>&gt;</span>
    )}
<span class="hljs-tag">&lt;/<span class="hljs-name">Formik</span>&gt;</span></span>
</code></pre>
<p><code>&lt;Formik&gt;</code> is a wrapper that takes 3 props. The <code>initialValues</code> that are defined above and passed here as props are then passed down to the Input fields defined in between.</p>
<pre><code class="lang-jsx">&lt;FieldArray {...field} name=<span class="hljs-string">"questions"</span> id=<span class="hljs-string">"questions"</span>&gt;
  {<span class="hljs-function">(<span class="hljs-params">fieldArrayProps</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { push, remove, form } = fieldArrayProps;
    <span class="hljs-keyword">const</span> { values, errors, touched } = form;
    <span class="hljs-keyword">const</span> { questions } = values;
    <span class="hljs-keyword">const</span> errorHandler = <span class="hljs-function">(<span class="hljs-params">name</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> error = getIn(errors, name);
      <span class="hljs-keyword">const</span> touch = getIn(touched, name);
      <span class="hljs-keyword">return</span> touch &amp;&amp; error ? error : <span class="hljs-literal">null</span>;
    };
    <span class="hljs-keyword">return</span> (<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> 
      // Input fields
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>)
  };
&lt;/FieldArray&gt;
</code></pre>
<p>Inside this form, you'll find that the <code>FieldArray</code> component is defined. This component is provided by Formik itself. When we want dynamic input fields, we can use this component.</p>
<p>The <code>fieldArrayProps</code> consists of two important elements named <code>push</code> and <code>remove</code> which helps us add a new input field and remove it.</p>
<p>We are using the <code>getIn</code> utility from Formik to validate our fields and check if there are any errors.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> validationSchema = yup.object().shape({
  title: yup.string().required(<span class="hljs-string">'Required'</span>),
  description: yup.string().required(<span class="hljs-string">'Required'</span>),
  questions: yup
    .array()
    .of(
      yup.object().shape({
        title: yup.string().required(<span class="hljs-string">'Required!'</span>),
        options: yup.array().of(
          yup.object().shape({
            title: yup.string().required(<span class="hljs-string">'Required!'</span>),
          })
        ),
      })
    )
    .required(<span class="hljs-string">'Must add a question'</span>),
});
</code></pre>
<p>Above is the Yup syntax which defines the object shape. For further information please refer to <a target="_blank" href="https://github.com/jquense/yup">yup's documentation</a>.</p>
<p>We combine the validation schema with Yup and pass it to Formik. Formik internally maps them with the name defined in the input field.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> submitHandler = <span class="hljs-keyword">async</span> (values, actions) =&gt; {
  <span class="hljs-keyword">try</span> {
    values = {
      ...values,
      createdAt: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
      updatedAt: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
      questions: values.questions.map(<span class="hljs-function">(<span class="hljs-params">question</span>) =&gt;</span> {
        <span class="hljs-keyword">return</span> {
          ...question,
          options: question.options.map(<span class="hljs-function">(<span class="hljs-params">option</span>) =&gt;</span> {
            <span class="hljs-keyword">return</span> { ...option, optionId: uuidv4() };
          }),
          questionId: uuidv4(),
        };
      }),
    };
    <span class="hljs-keyword">await</span> addQuizApi(auth, values);
    router.push(<span class="hljs-string">'/'</span>);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'error'</span>, error);
  } <span class="hljs-keyword">finally</span> {
    actions.setSubmitting(<span class="hljs-literal">false</span>);
  }
};
</code></pre>
<p>The <strong>onSubmit</strong> is invoked when a user clicks enter on the keyboard or presses the submit button on the website. We have to pass <code>submitHandler</code> as a reference to it.</p>
<p>Inside that function, we set a unique id for our questions and options and make an API call to store it on our Firestore collection.</p>
<p>Now inside the <strong>src</strong> &gt; <strong>utils</strong> directory, create a new file named <code>service.ts</code> and add the following code:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addQuizApi = <span class="hljs-keyword">async</span> (auth, values) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> header = {
      <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,
      token: auth.token,
    };
    <span class="hljs-keyword">const</span> resp = <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">'/api/quiz'</span>, values, { headers: header });
    <span class="hljs-keyword">return</span> resp;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> error;
  }
};
</code></pre>
<p>Inside the <strong>src &gt; pages</strong> directory create a new directory named <strong>api</strong>. All the files under this directory will run as the serverless environment by default.</p>
<p>Inside the <strong>api</strong> directory create a <strong>directory</strong> named <strong>quiz</strong>. Here create a new file named index.ts and paste in the following code:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { NextApiRequest, NextApiResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>;
<span class="hljs-keyword">import</span> { auth } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../lib/firebase-admin'</span>;
<span class="hljs-keyword">import</span> { addQuiz <span class="hljs-keyword">as</span> addQuizFb } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../utils/db'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> (req: NextApiRequest, res: NextApiResponse) =&gt; {
  <span class="hljs-keyword">switch</span> (req.method) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'POST'</span>:
      <span class="hljs-keyword">await</span> addQuiz(req, res);
      <span class="hljs-keyword">break</span>;
    <span class="hljs-keyword">default</span>:
      res.status(<span class="hljs-number">405</span>).json({ status: <span class="hljs-literal">false</span>, message: <span class="hljs-string">'Method Not found'</span> });
      <span class="hljs-keyword">break</span>;
  }
};

<span class="hljs-keyword">const</span> addQuiz = <span class="hljs-keyword">async</span> (req: NextApiRequest, res: NextApiResponse) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> auth.verifyIdToken(req.headers.token <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>);
    <span class="hljs-keyword">const</span> quizData = { ...req.body, userId: user.uid };
    <span class="hljs-keyword">await</span> addQuizFb(quizData);
    <span class="hljs-keyword">return</span> res
      .status(<span class="hljs-number">200</span>)
      .json({ status: <span class="hljs-literal">true</span>, message: <span class="hljs-string">'Quiz added successfully...'</span> });
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">return</span> res
      .status(<span class="hljs-number">500</span>)
      .json({ status: <span class="hljs-literal">false</span>, message: <span class="hljs-string">'Something went wrong'</span> });
  }
};
</code></pre>
<p>Now go to the <strong>src &gt; utils &gt; db.ts</strong> directory and add the following code after the <code>addUser</code> function:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addQuiz = <span class="hljs-keyword">async</span> (quizData) =&gt; {
  <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> firebase.firestore().collection(<span class="hljs-string">'quiz'</span>).add(quizData);
  <span class="hljs-keyword">return</span> response;
};
</code></pre>
<p>Now, let's run our development server and try to add a new quiz.</p>
<pre><code class="lang-shell">npm run dev
</code></pre>
<p>Go to <code>http://localhost:3000</code> and click on the <code>Add new quiz</code> link in the navbar. You'll get the following output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/screencapture-localhost-3000-quiz-new-2021-04-10-13_41_52.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now fill in the form and click on <strong>Submit Quiz</strong> button. Go to the Firebase console and you'll see that a new collection named <strong>quiz</strong> has been created.</p>
<p><strong>Note:</strong> For the <code>FIREBASE_PRIVATE_KEY</code> in <code>.env.local</code>, remember to add string quotation marks around it or you'll get the following error:</p>
<pre><code class="lang-shell">FirebaseAppError: Failed to parse private key: Error: Invalid PEM formatted message.
</code></pre>
<h3 id="heading-how-to-set-up-the-display-multiple-quizzes-mechanism">How to set up the Display Multiple Quizzes mechanism:</h3>
<p>Now let's show our quiz list on the <code>/</code> route. Go to the <strong>pages &gt; index.js</strong> and update the existing code with the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Box, Container, Divider, Flex, Heading, SimpleGrid, Text } <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;
<span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">'next/head'</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/router'</span>;
<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> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">'../common/Navbar'</span>;
<span class="hljs-keyword">import</span> { getAllQuiz, getAllUsers } <span class="hljs-keyword">from</span> <span class="hljs-string">'../utils/db'</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> quiz = <span class="hljs-built_in">JSON</span>.parse(props.quiz);
  <span class="hljs-keyword">const</span> router = useRouter();

  <span class="hljs-keyword">const</span> generateQuizCard = <span class="hljs-function">(<span class="hljs-params">singleQuiz</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">m</span>=<span class="hljs-string">{3}</span> <span class="hljs-attr">borderWidth</span>=<span class="hljs-string">"1px"</span> <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"lg"</span> <span class="hljs-attr">p</span>=<span class="hljs-string">{6}</span> <span class="hljs-attr">boxShadow</span>=<span class="hljs-string">"xl"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">as</span>=<span class="hljs-string">"h3"</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"lg"</span>&gt;</span>
          {singleQuiz.title}
        <span class="hljs-tag">&lt;/<span class="hljs-name">Heading</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">Text</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"gray.500"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{2}</span>&gt;</span>
            Posted By: {singleQuiz.user.name}
          <span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Text</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"gray.500"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{2}</span>&gt;</span>
            No of Questions: {singleQuiz.questions.length}
          <span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Divider</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{3}</span> <span class="hljs-attr">mb</span>=<span class="hljs-string">{3}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Text</span> <span class="hljs-attr">noOfLines</span>=<span class="hljs-string">{[1,</span> <span class="hljs-attr">2</span>, <span class="hljs-attr">3</span>]}&gt;</span>{singleQuiz.description}<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span></span>
    );
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Box</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>QuizApp<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <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">"/favicon.ico"</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">main</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">maxW</span>=<span class="hljs-string">"6xl"</span>&gt;</span>
            {quiz.length &gt; 0 &amp;&amp; (
              <span class="hljs-tag">&lt;<span class="hljs-name">SimpleGrid</span> <span class="hljs-attr">minChildWidth</span>=<span class="hljs-string">"400px"</span>&gt;</span>
                {quiz.map((singleQuiz) =&gt; (
                  <span class="hljs-tag">&lt;<span class="hljs-name">Box</span>
                    <span class="hljs-attr">key</span>=<span class="hljs-string">{singleQuiz.id}</span>
                    <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> router.push(`/quiz/${singleQuiz.id}`)}
                    as="button"
                    textAlign="start"
                    m={2}
                  &gt;
                    {generateQuizCard(singleQuiz)}
                  <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
                ))}
              <span class="hljs-tag">&lt;/<span class="hljs-name">SimpleGrid</span>&gt;</span>
            )}
          <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">footer</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getServerSideProps</span>(<span class="hljs-params">_context</span>) </span>{
  <span class="hljs-keyword">const</span> quiz = <span class="hljs-keyword">await</span> getAllQuiz();
  <span class="hljs-keyword">const</span> users = <span class="hljs-keyword">await</span> getAllUsers();
  <span class="hljs-keyword">const</span> data = quiz.map(<span class="hljs-function">(<span class="hljs-params">singleQuiz: any</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> { ...singleQuiz, <span class="hljs-attr">user</span>: users.find(<span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> user.id === singleQuiz.userId)};
  });
  <span class="hljs-keyword">return</span> { <span class="hljs-attr">props</span>: { <span class="hljs-attr">quiz</span>: <span class="hljs-built_in">JSON</span>.stringify(data) } };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Now go to the <strong>src &gt; utils &gt; db.ts</strong> and add the following after <code>addQuiz</code> function:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getAllQuiz = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> snapshot = <span class="hljs-keyword">await</span> firebase.firestore().collection(<span class="hljs-string">'quiz'</span>).get();
  <span class="hljs-keyword">const</span> quiz = snapshot.docs.map(<span class="hljs-function">(<span class="hljs-params">doc</span>) =&gt;</span> ({ id: doc.id, ...doc.data() }));
  <span class="hljs-keyword">return</span> quiz;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getAllUsers = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> snapshot = <span class="hljs-keyword">await</span> firebase.firestore().collection(<span class="hljs-string">'users'</span>).get();
  <span class="hljs-keyword">const</span> users = snapshot.docs.map(<span class="hljs-function">(<span class="hljs-params">doc</span>) =&gt;</span> ({ id: doc.id, ...doc.data() }));
  <span class="hljs-keyword">return</span> users;
}
</code></pre>
<p>Go to <code>http://localhost:3000</code> and refresh the page. You'll get the following output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/screencapture-localhost-3000-2021-04-10-14_49_25.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-show-a-single-quiz-how-to-answer-a-quiz-and-how-to-validate-the-answer">How to Show a Single Quiz, How to Answer a Quiz and How to Validate the Answer</h2>
<p>In this section following will be implemented:</p>
<ol>
<li><p>How to sett up the Show a Single Quiz and Answer Quiz mechanisms.</p>
</li>
<li><p>How to set up the Validate Answer mechanism.</p>
</li>
</ol>
<p>You can find the <strong>quiz app code</strong> implemented in this section at this <a target="_blank" href="https://github.com/Sharvin26/QuizApp/tree/ebc092727b9346b796a1d14fec6234e498403710">commit</a>.</p>
<h3 id="heading-how-to-set-up-the-show-a-single-quiz-and-answer-quiz-mechanisms"><strong>How to set up the Show a Single Quiz and Answer Quiz mechanisms</strong>:</h3>
<p>Create a new directory named <strong>[id]</strong> under <strong>src &gt; pages &gt; quiz.</strong> Inside this directory create a file named <code>index.tsx</code> and paste in the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> {
  Button,
  Center,
  Container,
  Divider,
  FormControl,
  FormLabel,
  Heading,
  HStack,
  RadioGroup,
  SimpleGrid,
  Text,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;
<span class="hljs-keyword">import</span> { Field, Form, Formik } <span class="hljs-keyword">from</span> <span class="hljs-string">'formik'</span>;
<span class="hljs-keyword">import</span> { NextPageContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/router'</span>;
<span class="hljs-keyword">import</span> React, { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../common/Navbar'</span>;
<span class="hljs-keyword">import</span> { useAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../lib/auth'</span>;
<span class="hljs-keyword">import</span> { getSingleQuiz } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../utils/db'</span>;
<span class="hljs-keyword">import</span> { addAnswerApi } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../utils/service'</span>;

<span class="hljs-keyword">const</span> ShowQuiz = <span class="hljs-function">(<span class="hljs-params">quiz, onSubmit</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Container</span>
      <span class="hljs-attr">maxW</span>=<span class="hljs-string">"7xl"</span>
      <span class="hljs-attr">mt</span>=<span class="hljs-string">{5}</span>
      <span class="hljs-attr">mb</span>=<span class="hljs-string">{5}</span>
      <span class="hljs-attr">borderWidth</span>=<span class="hljs-string">"1px"</span>
      <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"lg"</span>
      <span class="hljs-attr">p</span>=<span class="hljs-string">{6}</span>
      <span class="hljs-attr">boxShadow</span>=<span class="hljs-string">"xl"</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Center</span> <span class="hljs-attr">flexDirection</span>=<span class="hljs-string">"column"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span>&gt;</span>{quiz.title}<span class="hljs-tag">&lt;/<span class="hljs-name">Heading</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">Text</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{4}</span>&gt;</span>{quiz.description}<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{4}</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"lg"</span>&gt;</span>
        Questions:
      <span class="hljs-tag">&lt;/<span class="hljs-name">Heading</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Divider</span>
        <span class="hljs-attr">mt</span>=<span class="hljs-string">{4}</span>
        <span class="hljs-attr">mb</span>=<span class="hljs-string">{4}</span>
        <span class="hljs-attr">css</span>=<span class="hljs-string">{{</span>
          <span class="hljs-attr">boxShadow:</span> '<span class="hljs-attr">1px</span> <span class="hljs-attr">1px</span> #<span class="hljs-attr">888888</span>',
        }}
      /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Formik</span> <span class="hljs-attr">initialValues</span>=<span class="hljs-string">{{}}</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{onSubmit}</span>&gt;</span>
        {(props) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">Form</span>&gt;</span>
            {quiz.questions.map((singleQuiz, key) =&gt; (
              <span class="hljs-tag">&lt;<span class="hljs-name">Field</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{singleQuiz.questionId}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{key}</span>&gt;</span>
                {({ field, _form }) =&gt; (
                  <span class="hljs-tag">&lt;<span class="hljs-name">FormControl</span>
                    <span class="hljs-attr">as</span>=<span class="hljs-string">"fieldset"</span>
                    <span class="hljs-attr">isRequired</span>=<span class="hljs-string">{true}</span>
                    <span class="hljs-attr">mb</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">base:</span> <span class="hljs-attr">4</span>, <span class="hljs-attr">md:</span> <span class="hljs-attr">0</span> }}
                  &gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span> <span class="hljs-attr">as</span>=<span class="hljs-string">"legend"</span>&gt;</span>{singleQuiz.title}<span class="hljs-tag">&lt;/<span class="hljs-name">FormLabel</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">RadioGroup</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">SimpleGrid</span> <span class="hljs-attr">minChildWidth</span>=<span class="hljs-string">"120px"</span> <span class="hljs-attr">mb</span>=<span class="hljs-string">{2}</span>&gt;</span>
                        {singleQuiz.options.map((option, subkey) =&gt; (
                          <span class="hljs-tag">&lt;<span class="hljs-name">HStack</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{subkey}</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Field</span>
                              {<span class="hljs-attr">...field</span>}
                              <span class="hljs-attr">type</span>=<span class="hljs-string">"radio"</span>
                              <span class="hljs-attr">name</span>=<span class="hljs-string">{singleQuiz.questionId}</span>
                              <span class="hljs-attr">value</span>=<span class="hljs-string">{option.optionId}</span>
                            /&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>&gt;</span>{option.title}<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
                          <span class="hljs-tag">&lt;/<span class="hljs-name">HStack</span>&gt;</span>
                        ))}
                      <span class="hljs-tag">&lt;/<span class="hljs-name">SimpleGrid</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">RadioGroup</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">FormControl</span>&gt;</span>
                )}
              <span class="hljs-tag">&lt;/<span class="hljs-name">Field</span>&gt;</span>
            ))}
            <span class="hljs-tag">&lt;<span class="hljs-name">Center</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{10}</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">isLoading</span>=<span class="hljs-string">{props.isSubmitting}</span>
                <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"green"</span>
              &gt;</span>
                Submit
              <span class="hljs-tag">&lt;/<span class="hljs-name">Button</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">Form</span>&gt;</span>
        )}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Formik</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">const</span> SingleQuiz = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { auth, loading } = useAuth();

  <span class="hljs-keyword">const</span> router = useRouter();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (!auth &amp;&amp; !loading) {
      router.push(<span class="hljs-string">`/signin?next=/quiz/<span class="hljs-subst">${props.quizId}</span>`</span>);
    }
  }, [auth, loading]);

  <span class="hljs-keyword">const</span> quiz = <span class="hljs-built_in">JSON</span>.parse(props.quiz);

  <span class="hljs-keyword">const</span> onSubmit = <span class="hljs-keyword">async</span> (values, actions) =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> resp = <span class="hljs-keyword">await</span> addAnswerApi(auth, props.quizId, values);
      <span class="hljs-keyword">const</span> answerId = resp.data.data.answerId;
      router.push(<span class="hljs-string">`/quiz/<span class="hljs-subst">${props.quizId}</span>/answer/<span class="hljs-subst">${answerId}</span>`</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'error'</span>, error);
    } <span class="hljs-keyword">finally</span> {
      actions.setSubmitting(<span class="hljs-literal">false</span>);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
      {quiz &amp;&amp; ShowQuiz(quiz, onSubmit)}
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getServerSideProps</span>(<span class="hljs-params">context: NextPageContext</span>) </span>{
  <span class="hljs-keyword">const</span> quizId = context.query.id;
  <span class="hljs-keyword">const</span> quizData = <span class="hljs-keyword">await</span> getSingleQuiz(quizId);
  <span class="hljs-keyword">return</span> { <span class="hljs-attr">props</span>: { <span class="hljs-attr">quiz</span>: quizData, quizId } };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> SingleQuiz;
</code></pre>
<p>Inside <strong>src &gt; utils &gt;</strong> <code>db.ts</code> add the following code below the <code>getAllUsers</code> function:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getSingleQuiz = <span class="hljs-keyword">async</span> (quizId) =&gt; {
  <span class="hljs-keyword">const</span> snapshot = <span class="hljs-keyword">await</span> firebase
    .firestore()
    .collection(<span class="hljs-string">'quiz'</span>)
    .doc(<span class="hljs-built_in">String</span>(quizId))
    .get();
  <span class="hljs-keyword">const</span> quizData = snapshot.exists ? <span class="hljs-built_in">JSON</span>.stringify(snapshot.data()) : <span class="hljs-literal">null</span>;
  <span class="hljs-keyword">return</span> quizData;
};
</code></pre>
<p>Inside <strong>src &gt; utils &gt;</strong> <code>service.ts</code> add the following code below the <code>addQuizApi</code> function:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addAnswerApi = <span class="hljs-keyword">async</span> (auth, quizId, values) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> header = {
      <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,
      token: auth.token,
    };
    <span class="hljs-keyword">const</span> resp = <span class="hljs-keyword">await</span> axios.post(
      <span class="hljs-string">`/api/quiz/<span class="hljs-subst">${quizId}</span>/answer`</span>,
      {
        questions: values,
        createdAt: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
        updatedAt: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
      },
      { headers: header }
    );
    <span class="hljs-keyword">return</span> resp;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">throw</span> error;
  }
};
</code></pre>
<p>Inside <strong>src &gt; pages &gt; api &gt; quiz</strong> directory, create a new directory named <strong>[id]</strong>.</p>
<h3 id="heading-how-to-set-up-the-validate-answer-mechanism">How to set up the Validate Answer mechanism:</h3>
<p>Inside this directory create a file named <code>answer.ts</code> and paste in the following code:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { NextApiRequest, NextApiResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>;
<span class="hljs-keyword">import</span> { auth } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../../lib/firebase-admin'</span>;
<span class="hljs-keyword">import</span> { addAnswer <span class="hljs-keyword">as</span> addAnswerFb } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../../utils/db'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> (req: NextApiRequest, res: NextApiResponse) =&gt; {
  <span class="hljs-keyword">switch</span> (req.method) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'POST'</span>:
      <span class="hljs-keyword">await</span> addAnswer(req, res);
      <span class="hljs-keyword">break</span>;
    <span class="hljs-keyword">default</span>:
      res.status(<span class="hljs-number">405</span>).json({ status: <span class="hljs-literal">false</span>, message: <span class="hljs-string">'Method Not found'</span> });
      <span class="hljs-keyword">break</span>;
  }
};

<span class="hljs-keyword">const</span> addAnswer = <span class="hljs-keyword">async</span> (req: NextApiRequest, res: NextApiResponse) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> auth.verifyIdToken(req.headers.token <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>);
    <span class="hljs-keyword">const</span> data = {
      ...req.body,
      quizId: req.query.id,
      userId: user.uid,
    };
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> addAnswerFb(data);
    <span class="hljs-keyword">return</span> res
      .status(<span class="hljs-number">200</span>)
      .json({ status: <span class="hljs-literal">true</span>, data: { answerId: response.id } });
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">return</span> res
      .status(<span class="hljs-number">500</span>)
      .json({ status: <span class="hljs-literal">false</span>, message: <span class="hljs-string">'Something went wrong'</span> });
  }
};
</code></pre>
<p>Inside <strong>src &gt; utils &gt;</strong> <code>db.ts</code> add the following code below the <code>getSingleQuiz</code> function:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addAnswer = <span class="hljs-keyword">async</span> (data) =&gt; {
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> firebase.firestore().collection(<span class="hljs-string">'answer'</span>).add(data);
  <span class="hljs-keyword">return</span> response;
};
</code></pre>
<p>Go to <code>http://localhost:3000</code>, refresh the page, and click on the quiz. You'll get the following output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/screencapture-localhost-3000-quiz-1VrjhRht5LFdA3a2all5-2021-04-10-15_13_15.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now you can answer the question and press submit. Right now it will go to a 404 page. We will need to create a page where we can show the correct answer.</p>
<p>Inside the <strong>src &gt; pages &gt; quiz &gt; [id]</strong> directory, create a new directory called <strong>answer</strong>. Inside that directory create a new file called <code>[answerId].tsx</code> and paste in the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> {
  Box,
  Center,
  Container,
  Divider,
  Heading,
  Radio,
  RadioGroup,
  SimpleGrid,
  Text,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;
<span class="hljs-keyword">import</span> { NextPageContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>;
<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> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../../common/Navbar'</span>;
<span class="hljs-keyword">import</span> { getAnswer, getSingleQuiz } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../../utils/db'</span>;

<span class="hljs-keyword">const</span> answer = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> quiz = <span class="hljs-built_in">JSON</span>.parse(props.quiz);
  <span class="hljs-keyword">const</span> answer = <span class="hljs-built_in">JSON</span>.parse(props.answer);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
      {quiz &amp;&amp; answer &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">maxW</span>=<span class="hljs-string">"3xl"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{5}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Center</span> <span class="hljs-attr">flexDirection</span>=<span class="hljs-string">"column"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span>&gt;</span>Correct Answer for {quiz.title}<span class="hljs-tag">&lt;/<span class="hljs-name">Heading</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Text</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{4}</span>&gt;</span>{quiz.description}<span class="hljs-tag">&lt;/<span class="hljs-name">Text</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>
            <span class="hljs-attr">mt</span>=<span class="hljs-string">{4}</span>
            <span class="hljs-attr">mb</span>=<span class="hljs-string">{4}</span>
            <span class="hljs-attr">css</span>=<span class="hljs-string">{{</span>
              <span class="hljs-attr">boxShadow:</span> '<span class="hljs-attr">1px</span> <span class="hljs-attr">1px</span> #<span class="hljs-attr">888888</span>',
            }}
          /&gt;</span>
          {quiz.questions.map((singleQuiz, index) =&gt; {
            return (
              <span class="hljs-tag">&lt;<span class="hljs-name">Box</span>
                <span class="hljs-attr">mt</span>=<span class="hljs-string">{index</span> !== <span class="hljs-string">0</span> &amp;&amp; <span class="hljs-attr">4</span>}
                <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>
                <span class="hljs-attr">borderWidth</span>=<span class="hljs-string">"1px"</span>
                <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"lg"</span>
                <span class="hljs-attr">p</span>=<span class="hljs-string">{6}</span>
                <span class="hljs-attr">boxShadow</span>=<span class="hljs-string">"xl"</span>
                <span class="hljs-attr">backgroundColor</span>=<span class="hljs-string">{</span>
                  <span class="hljs-attr">answer.questions</span>[<span class="hljs-attr">singleQuiz.questionId</span>] &amp;&amp;
                  <span class="hljs-attr">singleQuiz.options</span>[<span class="hljs-attr">singleQuiz.answer</span>]<span class="hljs-attr">.optionId</span> ===
                    <span class="hljs-string">answer.questions[singleQuiz.questionId]</span>
                    ? '<span class="hljs-attr">green.200</span>'
                    <span class="hljs-attr">:</span> '<span class="hljs-attr">red.200</span>'
                }
              &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>&gt;</span>
                  {index + 1}) {singleQuiz.title}
                <span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">RadioGroup</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">SimpleGrid</span> <span class="hljs-attr">minChildWidth</span>=<span class="hljs-string">"120px"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{2}</span>&gt;</span>
                    {singleQuiz.options.map((option, index) =&gt; (
                      <span class="hljs-tag">&lt;<span class="hljs-name">Radio</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{option.title}</span> <span class="hljs-attr">isDisabled</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>
                        {option.title}
                      <span class="hljs-tag">&lt;/<span class="hljs-name">Radio</span>&gt;</span>
                    ))}
                  <span class="hljs-tag">&lt;/<span class="hljs-name">SimpleGrid</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">RadioGroup</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Text</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{3}</span>&gt;</span>
                  Correct Answer: {singleQuiz.options[singleQuiz.answer].title}
                <span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
                {answer.questions[singleQuiz.questionId] ? (
                  <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>&gt;</span>
                    Selected Answer:{' '}
                    {
                      singleQuiz.options.find(
                        (option) =&gt;
                          option.optionId ===
                          answer.questions[singleQuiz.questionId]
                      ).title
                    }
                  <span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
                ) : (
                  <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>&gt;</span>Not Answered<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
                )}
              <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
            );
          })}
        <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getServerSideProps</span>(<span class="hljs-params">context: NextPageContext</span>) </span>{
  <span class="hljs-keyword">const</span> quizId = context.query.id;
  <span class="hljs-keyword">const</span> answerId = context.query.answerId;
  <span class="hljs-keyword">const</span> quizData = <span class="hljs-keyword">await</span> getSingleQuiz(quizId);
  <span class="hljs-keyword">const</span> answerData = <span class="hljs-keyword">await</span> getAnswer(answerId);
  <span class="hljs-keyword">return</span> { <span class="hljs-attr">props</span>: { <span class="hljs-attr">answer</span>: answerData, <span class="hljs-attr">quiz</span>: quizData } };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> answer;
</code></pre>
<p>Inside <strong>src &gt; utils &gt;</strong> <code>db.ts</code> add the following code below the <code>addAnswer</code> function:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getAnswer = <span class="hljs-keyword">async</span> (answerId) =&gt; {
  <span class="hljs-keyword">const</span> answerSnapshot = <span class="hljs-keyword">await</span> firebase
    .firestore()
    .collection(<span class="hljs-string">'answer'</span>)
    .doc(<span class="hljs-built_in">String</span>(answerId))
    .get();
  <span class="hljs-keyword">let</span> answerData = answerSnapshot.exists
    ? <span class="hljs-built_in">JSON</span>.stringify(answerSnapshot.data())
    : <span class="hljs-literal">null</span>;
  <span class="hljs-keyword">return</span> answerData;
};
</code></pre>
<p>Go to <code>http://localhost:3000</code>, refresh the page, click on the quiz and answer the question. You'll get the following output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/screencapture-localhost-3000-quiz-1VrjhRht5LFdA3a2all5-answer-jyZ3cOPbfyPX4DyGduUD-2021-04-10-15_40_40.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>With this, we have completed our application and it's ready to be deployed on Vercel. In the next section, we will configure the deployment mechanism.</p>
<h2 id="heading-how-to-deploy-the-app-to-vercel-and-firebase-authentication-configuration">How to Deploy the App to Vercel and Firebase Authentication Configuration</h2>
<p>There are two ways to configure an application on Vercel:</p>
<ol>
<li><p>Using the <a target="_blank" href="https://www.npmjs.com/package/vercel">Vercel npm library</a> and pushing the code locally to a Vercel server</p>
</li>
<li><p>Connecting the Vercel bot to the GitHub repository.</p>
</li>
</ol>
<p>I am going to use the second method.</p>
<p>You need to create a repository on GitHub and push the code over there.</p>
<p>If you haven't created an account on Vercel then you can go to <a target="_blank" href="https://vercel.com/">https://vercel.com/</a> and click on the sign up button.</p>
<p>Once you've created your account you'll be directed to a dashboard that looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-10-at-4.07.03-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click on the <strong>New Project</strong> button. It will ask you to install the Vercel bot and permissions.</p>
<p><strong>Note:</strong> You can allow the Vercel bot to read all repositories from your GitHub account or give permission for the currently created repository.</p>
<p>Click the Import button on the GitHub repository created above:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-10-at-4.12.06-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now you'll need to add environment variables. Add them from <code>.env.local</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/screencapture-vercel-new-settings-2021-04-10-16_18_04.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Once they are added click on the Deploy button. After the deployment is successful you'll get the following screen.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-10-at-4.22.02-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><strong>Note:</strong> the URL may be in this format -&lt;username-or_something_random&gt;.vercel.app.</p>
<p>Our Sign In won't work now. We have to add our new URL to the allowed URLs in the Firebase console.</p>
<p>Go to the <strong>Firebase console &gt; Authentication</strong> and click on <strong>Sign-in-methods</strong> and scroll down. You'll see the <strong>Authorized domains</strong> table.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Screenshot-2021-04-10-at-4.32.41-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click on the Add domain button, copy the newly generated URL, and click on add. Now open the deployed quiz application and test it.</p>
<p><strong>Note:</strong> If you receive an error while adding a new quiz or answering the quiz, go to <strong>Vercel dashboard &gt; Select the project &gt; Select the settings tab &gt; Select Environment Variables</strong> and update your <code>FIREBASE_PRIVATE_KEY</code> once again.</p>
<p>With this, we have created our production-ready quiz application. If you have built the app along with the tutorial, then a very big congratulations to you on this achievement.</p>
<h2 id="heading-next-steps">Next Steps:</h2>
<p>If you want to build more features into this app, here are few next steps you can consider:</p>
<ol>
<li><p>Dashboard for users. (Show Profile Information, Update, and Delete. Show Quiz Added, Update and Delete. Show Quiz Answer.)</p>
</li>
<li><p>Firestore security rules modification.</p>
</li>
<li><p>Rich text markdown for Quiz questions and options.</p>
</li>
</ol>
<p>Thank you for reading!</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>
<p>If you want any project to be developed or want to consult with me, you can DM me on my Twitter (@sharvin26).</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Design an iMessage-like Chat Bubble in React Native ]]>
                </title>
                <description>
                    <![CDATA[ By Prajwal Kulkarni Whether you're an Apple fan or not, you'll likely agree that Apple sure does have a groundbreaking UI. And iMessage is definitely an important part of that design.  The curved arrow is something that I have always really liked and... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/design-imessage-like-chat-bubble-react-native/</link>
                <guid isPermaLink="false">66d4608be39d8b5612bc0deb</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Chat ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React Native ]]>
                    </category>
                
                    <category>
                        <![CDATA[ UI Design ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 24 Mar 2021 18:50:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/03/feature_image_freecodecamp-3.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Prajwal Kulkarni</p>
<p>Whether you're an Apple fan or not, you'll likely agree that Apple sure does have a groundbreaking UI. And iMessage is definitely an important part of that design. </p>
<p>The curved arrow is something that I have always really liked and have wanted to replicate for a long time.</p>
<p>After a lot of trial and error, I was finally able to find a workaround to build a similar version of iMessage's chat bubble. In this article, I'll take you through the steps required to build a chat bubble that looks like Apple's iMessage.</p>
<p>If you're building a chat application or intending to display information in the form of a message, I'd definitely recommend that you try out this style as it makes your app look cool and professional.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>This article assumes that you know the basics of:</p>
<ul>
<li>JSX </li>
<li>React Native </li>
<li>HTML &amp; CSS</li>
</ul>
<h2 id="heading-what-is-a-chat-bubble">What is a Chat Bubble?</h2>
<p>A chat bubble is basically a container that holds text. Chat bubbles are mostly used in Instant Messaging apps to display chat logs effectively. </p>
<p>The conventional method is that sent messages are displayed on the right side of the screen and received messages are shown on the left, with different colors used to differentiate between sent and received message(s).</p>
<p>Most messaging apps have a basic chat bubble which is a regular container with rounded corners. The main differentiating factor between other apps and iMessage is the presence of a small curved-like arrow anchoring the text container, which looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/freecodecamp-1.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-build-a-chat-bubble-that-looks-like-imessage">How to Build a Chat Bubble that Looks like iMessage</h2>
<p>If we look at the above image carefully, we can see that the iMessage chat bubble is a combination of a regular chat bubble with an added arrow in the corner.</p>
<p>The main challenge lies in tying the arrow to the text container.</p>
<p>Before directly hopping into the code, I'd want you to know how this arrow-like element is created and added.</p>
<p>First, check out <a target="_blank" href="https://codepen.io/samuelkraft/pen/Farhl">this</a> code, which shows how to implementation this arrow using HTML &amp; CSS. Below is its code snippet.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">255px</span>;
  <span class="hljs-attribute">word-wrap</span>: break-word;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">12px</span>;
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">24px</span>;
  <span class="hljs-attribute">position</span>: relative;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">25px</span>;

  &amp;:before, &amp;:after {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
        <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">bottom</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
  }
}

<span class="hljs-selector-class">.from-me</span> {
    <span class="hljs-attribute">color</span>: white; 
    <span class="hljs-attribute">background</span>: <span class="hljs-number">#0B93F6</span>;
    <span class="hljs-attribute">align-self</span>: flex-end;

    &amp;:before {
        <span class="hljs-attribute">right</span>: -<span class="hljs-number">7px</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#0B93F6</span>;
        <span class="hljs-attribute">border-bottom-left-radius</span>: <span class="hljs-number">16px</span> <span class="hljs-number">14px</span>;
    }

    &amp;<span class="hljs-selector-pseudo">:after</span> {
        <span class="hljs-attribute">right</span>: -<span class="hljs-number">26px</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">26px</span>;
    <span class="hljs-attribute">background-color</span>: white;
        <span class="hljs-attribute">border-bottom-left-radius</span>: <span class="hljs-number">10px</span>;
    }
}
<span class="hljs-selector-class">.from-them</span> {
    <span class="hljs-attribute">background</span>: <span class="hljs-number">#E5E5EA</span>;
    <span class="hljs-attribute">color</span>: black;
  <span class="hljs-attribute">align-self</span>: flex-start;

    &amp;:before {
        <span class="hljs-attribute">left</span>: -<span class="hljs-number">7px</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#E5E5EA</span>;
        <span class="hljs-attribute">border-bottom-right-radius</span>: <span class="hljs-number">16px</span>;
    }

    &amp;<span class="hljs-selector-pseudo">:after</span> {
        <span class="hljs-attribute">left</span>: -<span class="hljs-number">26px</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">26px</span>;
    <span class="hljs-attribute">background-color</span>: white;
        <span class="hljs-attribute">border-bottom-right-radius</span>: <span class="hljs-number">10px</span>;
    }
}
</code></pre>
<p>If you just browse straight through the code it might seem quite awful. So let's break it down at an atomic level and later glue it all back together.</p>
<p>The <code>&lt;**p&gt;**</code> tag includes style constraints such as margin-bottom, position, padding and so on. Note that the max-width used here is 255px, which is a static value. But we'll be using a dynamic approach, as the chat bubbles need to be responsive across various screen sizes.</p>
<p>The <code>&amp;:before</code> and <code>&amp;:after</code> within the <strong><code>&lt;p&gt;</code></strong> style defines two elements with no content in it. They're positioned absolute with respect to the <strong><code>&lt;p&gt;</code></strong> tag (text container), and are placed at the bottom. They have a height of 25px (the height of the arrow).</p>
<p>Going further, the <code>.from-me</code> (sent messages) style defines that the text be white, background blue (#0b936f), and that it's placed at the right side of the screen (align-self: flex-end). </p>
<p>Now comes the important part – extending the <strong><code>&amp;:before</code></strong> and <strong><code>&amp;:after</code>,</strong> which is the actual implementation of the arrow.</p>
<p>The <strong><code>&amp;:before</code></strong> has a width of 20px and is placed at 7 pixels negative to the right. It has a border-bottom-left radius of 16px, which is what gives the curved look to the arrow.</p>
<p>Similarly, the <strong><code>&amp;:after</code></strong> has a width of 26px and is placed at 26 pixels negative to the right. Since -7px &gt; -26px, <code>&amp;:after</code> is placed right side of the <code>&amp;:before</code> element and partially overlaps it.</p>
<p>If you still feel confused, don't worry – just refer to the images below to gain a clearer insight into what I've been talking about.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/fcc1.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>&amp;:before with black background and bottom-left-radius</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/fcc2.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>&amp;:after overlapping &amp;:before with green background</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/fcc3.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>&amp;:after background changed to white to match the background of the chat screen.</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/fcc4.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>&amp;:before background updated to #0b93f6 to match chat bubble color.</em></p>
<p>So basically the arrowhead is created by overlapping two elements at the bottom corner of the chat bubble and adjusting the background colors to match those of the chat bubble and chat screen.</p>
<p>Further ahead, the translation of CSS and HTML into JSX is fairly simple, as most of the things are quite straightforward.</p>
<h2 id="heading-how-to-build-the-react-native-version">How to Build the React Native Version</h2>
<p>Before starting, I want to note that this works best with FlatList, and I recommend that you use it, and not other components or functions such as map (which lacked consistency across different screens and devices). </p>
<p>The three steps we're going to follow here are:</p>
<ol>
<li>Create chat bubble with arrow head</li>
<li>Add styles to chat bubble and arrow head</li>
<li>Embed chat bubble in FlatList</li>
</ol>
<p>So let's get started.</p>
<p>First, we'll create the chat bubble with the arrow head, like this:</p>
<pre><code>&lt;View style={{
                    <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"#0078fe"</span>,
                    <span class="hljs-attr">padding</span>:<span class="hljs-number">10</span>,
                    <span class="hljs-attr">marginLeft</span>: <span class="hljs-string">'45%'</span>,
                    <span class="hljs-attr">borderRadius</span>: <span class="hljs-number">5</span>,
                    <span class="hljs-comment">//marginBottom: 15,</span>
                    <span class="hljs-attr">marginTop</span>: <span class="hljs-number">5</span>,
                    <span class="hljs-attr">marginRight</span>: <span class="hljs-string">"5%"</span>,
                    <span class="hljs-attr">maxWidth</span>: <span class="hljs-string">'50%'</span>,
                    <span class="hljs-attr">alignSelf</span>: <span class="hljs-string">'flex-end'</span>,
                    <span class="hljs-comment">//maxWidth: 500,</span>

                    <span class="hljs-attr">borderRadius</span>: <span class="hljs-number">20</span>,
                  }} key={index}&gt;


                    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Text</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">fontSize:</span> <span class="hljs-attr">16</span>, <span class="hljs-attr">color:</span> "#<span class="hljs-attr">fff</span>", }} <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>{item.text}<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span></span>

                      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{styles.rightArrow}</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">View</span>&gt;</span></span>

                      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{styles.rightArrowOverlap}</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">View</span>&gt;</span></span>



&lt;/View&gt;


<span class="hljs-comment">//Recevied Message</span>
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
                    <span class="hljs-attr">backgroundColor:</span> "#<span class="hljs-attr">dedede</span>",
                    <span class="hljs-attr">padding:10</span>,
                    <span class="hljs-attr">borderRadius:</span> <span class="hljs-attr">5</span>,
                    <span class="hljs-attr">marginTop:</span> <span class="hljs-attr">5</span>,
                    <span class="hljs-attr">marginLeft:</span> "<span class="hljs-attr">5</span>%",
                    <span class="hljs-attr">maxWidth:</span> '<span class="hljs-attr">50</span>%',
                    <span class="hljs-attr">alignSelf:</span> '<span class="hljs-attr">flex-start</span>',
                    //<span class="hljs-attr">maxWidth:</span> <span class="hljs-attr">500</span>,
                    //<span class="hljs-attr">padding:</span> <span class="hljs-attr">14</span>,

                    //<span class="hljs-attr">alignItems:</span>"<span class="hljs-attr">center</span>",
                    <span class="hljs-attr">borderRadius:</span> <span class="hljs-attr">20</span>,
                  }} <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>



                      <span class="hljs-tag">&lt;<span class="hljs-name">Text</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">fontSize:</span> <span class="hljs-attr">16</span>, <span class="hljs-attr">color:</span> "#<span class="hljs-attr">000</span>",<span class="hljs-attr">justifyContent:</span>"<span class="hljs-attr">center</span>" }} <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span> {item.text}<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{styles.leftArrow}</span>&gt;</span>

                      <span class="hljs-tag">&lt;/<span class="hljs-name">View</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{styles.leftArrowOverlap}</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">View</span>&gt;</span>



                    <span class="hljs-tag">&lt;/<span class="hljs-name">View</span>&gt;</span></span>
</code></pre><p>The Outermost <strong><code>&lt;View&gt;</code></strong> tag acts as the 'p' tag in comparison with the HTML version. The remaining two <strong><code>&lt;View&gt;</code></strong> tags act as <code>&amp;:before</code> and <code>&amp;:after</code>.</p>
<p>Next, we'll add styles to the chat bubble and arrow head like this:</p>
<pre><code><span class="hljs-keyword">const</span> styles = StyleSheet.create({
<span class="hljs-attr">rightArrow</span>: {
  <span class="hljs-attr">position</span>: <span class="hljs-string">"absolute"</span>,
  <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"#0078fe"</span>,
  <span class="hljs-comment">//backgroundColor:"red",</span>
  <span class="hljs-attr">width</span>: <span class="hljs-number">20</span>,
  <span class="hljs-attr">height</span>: <span class="hljs-number">25</span>,
  <span class="hljs-attr">bottom</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">borderBottomLeftRadius</span>: <span class="hljs-number">25</span>,
  <span class="hljs-attr">right</span>: <span class="hljs-number">-10</span>
},

<span class="hljs-attr">rightArrowOverlap</span>: {
  <span class="hljs-attr">position</span>: <span class="hljs-string">"absolute"</span>,
  <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"#eeeeee"</span>,
  <span class="hljs-comment">//backgroundColor:"green",</span>
  <span class="hljs-attr">width</span>: <span class="hljs-number">20</span>,
  <span class="hljs-attr">height</span>: <span class="hljs-number">35</span>,
  <span class="hljs-attr">bottom</span>: <span class="hljs-number">-6</span>,
  <span class="hljs-attr">borderBottomLeftRadius</span>: <span class="hljs-number">18</span>,
  <span class="hljs-attr">right</span>: <span class="hljs-number">-20</span>

},

<span class="hljs-comment">/*Arrow head for recevied messages*/</span>
<span class="hljs-attr">leftArrow</span>: {
    <span class="hljs-attr">position</span>: <span class="hljs-string">"absolute"</span>,
    <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"#dedede"</span>,
    <span class="hljs-comment">//backgroundColor:"red",</span>
    <span class="hljs-attr">width</span>: <span class="hljs-number">20</span>,
    <span class="hljs-attr">height</span>: <span class="hljs-number">25</span>,
    <span class="hljs-attr">bottom</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">borderBottomRightRadius</span>: <span class="hljs-number">25</span>,
    <span class="hljs-attr">left</span>: <span class="hljs-number">-10</span>
},

<span class="hljs-attr">leftArrowOverlap</span>: {
    <span class="hljs-attr">position</span>: <span class="hljs-string">"absolute"</span>,
    <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"#eeeeee"</span>,
    <span class="hljs-comment">//backgroundColor:"green",</span>
    <span class="hljs-attr">width</span>: <span class="hljs-number">20</span>,
    <span class="hljs-attr">height</span>: <span class="hljs-number">35</span>,
    <span class="hljs-attr">bottom</span>: <span class="hljs-number">-6</span>,
    <span class="hljs-attr">borderBottomRightRadius</span>: <span class="hljs-number">18</span>,
    <span class="hljs-attr">left</span>: <span class="hljs-number">-20</span>

},
})
</code></pre><p>Then we'll embed it into FlatList:</p>
<pre><code>&lt;FlatList
        <span class="hljs-comment">//inverted</span>
        style={{<span class="hljs-attr">backgroundColor</span>:<span class="hljs-string">"#eeeeee"</span>}}
        data={<span class="hljs-built_in">this</span>.state.chat_log}
        ref={<span class="hljs-function"><span class="hljs-params">ref</span> =&gt;</span> (<span class="hljs-built_in">this</span>.FlatListRef = ref)} <span class="hljs-comment">// assign the flatlist's ref to your component's FlatListRef...</span>


        renderItem = {<span class="hljs-function">(<span class="hljs-params">{item,index}</span>)=&gt;</span>{

          rowId={index}

            <span class="hljs-keyword">if</span> (SENT_MESSAGE) { <span class="hljs-comment">//change as per your code logic</span>



                <span class="hljs-keyword">return</span> (

                  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
                    <span class="hljs-attr">backgroundColor:</span> "#<span class="hljs-attr">0078fe</span>",
                    <span class="hljs-attr">padding:10</span>,
                    <span class="hljs-attr">marginLeft:</span> '<span class="hljs-attr">45</span>%',
                    <span class="hljs-attr">borderRadius:</span> <span class="hljs-attr">5</span>,

                    <span class="hljs-attr">marginTop:</span> <span class="hljs-attr">5</span>,
                    <span class="hljs-attr">marginRight:</span> "<span class="hljs-attr">5</span>%",
                    <span class="hljs-attr">maxWidth:</span> '<span class="hljs-attr">50</span>%',
                    <span class="hljs-attr">alignSelf:</span> '<span class="hljs-attr">flex-end</span>',
                    <span class="hljs-attr">borderRadius:</span> <span class="hljs-attr">20</span>,
                  }} <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>


                    <span class="hljs-tag">&lt;<span class="hljs-name">Text</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">fontSize:</span> <span class="hljs-attr">16</span>, <span class="hljs-attr">color:</span> "#<span class="hljs-attr">fff</span>", }} <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span> {item.text}<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>

                      <span class="hljs-tag">&lt;<span class="hljs-name">View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{styles.rightArrow}</span>&gt;</span>

                      <span class="hljs-tag">&lt;/<span class="hljs-name">View</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{styles.rightArrowOverlap}</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">View</span>&gt;</span>



                  <span class="hljs-tag">&lt;/<span class="hljs-name">View</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">View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
                    <span class="hljs-attr">backgroundColor:</span> "#<span class="hljs-attr">dedede</span>",
                    <span class="hljs-attr">padding:10</span>,
                    <span class="hljs-attr">borderRadius:</span> <span class="hljs-attr">5</span>,
                    <span class="hljs-attr">marginTop:</span> <span class="hljs-attr">5</span>,
                    <span class="hljs-attr">marginLeft:</span> "<span class="hljs-attr">5</span>%",
                    <span class="hljs-attr">maxWidth:</span> '<span class="hljs-attr">50</span>%',
                    <span class="hljs-attr">alignSelf:</span> '<span class="hljs-attr">flex-start</span>',
                    //<span class="hljs-attr">maxWidth:</span> <span class="hljs-attr">500</span>,
                    //<span class="hljs-attr">padding:</span> <span class="hljs-attr">14</span>,

                    //<span class="hljs-attr">alignItems:</span>"<span class="hljs-attr">center</span>",
                    <span class="hljs-attr">borderRadius:</span> <span class="hljs-attr">20</span>,
                  }} <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>



                      <span class="hljs-tag">&lt;<span class="hljs-name">Text</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">fontSize:</span> <span class="hljs-attr">16</span>, <span class="hljs-attr">color:</span> "#<span class="hljs-attr">000</span>",<span class="hljs-attr">justifyContent:</span>"<span class="hljs-attr">center</span>" }} <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span> {item.text}<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{styles.leftArrow}</span>&gt;</span>

                      <span class="hljs-tag">&lt;/<span class="hljs-name">View</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{styles.leftArrowOverlap}</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">View</span>&gt;</span>



                  <span class="hljs-tag">&lt;/<span class="hljs-name">View</span>&gt;</span></span>
                )


            }



        }

        keyExtractor={<span class="hljs-function">(<span class="hljs-params">item,index</span>)=&gt;</span>index.toString()}
        /&gt;
</code></pre><p>Values such as <strong>borderRadius, padding, margin,</strong> and <strong>backgroundColor</strong> are arbitrary values and can be changed if you wish. So feel free to play around and make those changes to best fit your requirements.</p>
<p>The result of the above code looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/IMG_20210324_160111.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Chat bubble appearance, as tested on several devices(Android).</em></p>
<p>Looks cool, doesn't it ? ;)</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations! You've built a chat bubble that looks just like the one iMessage uses.</p>
<p>I hope you found this article helpful. If so, do share it with your friends and colleagues.</p>
<p>Still have questions? Don't hesitate to get in touch with me, and I'll respond to you as soon as possible.</p>
<p>You could also connect with me on <a target="_blank" href="https://in.linkedin.com/in/prajwal-kulkarni">LinkedIn</a> / <a target="_blank" href="https://instagram.com/prajwalkulkarni_">Instagram</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Build a React Budget Tracker App – Learn React & Context API with this Fun Project ]]>
                </title>
                <description>
                    <![CDATA[ In this React Budget Tracker App tutorial we're going to: We’ll learn how break down a UI into React components Learn how to work with state using the Context API Learn about actions, reducers, and the dispatch function  And I’ll give you some chal... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/react-budget-tracker-app/</link>
                <guid isPermaLink="false">66c8c8fd85ffc69fd028a826</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React context ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chris Blakely ]]>
                </dc:creator>
                <pubDate>Fri, 12 Mar 2021 19:24:55 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/03/react-budget-app-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this React Budget Tracker App tutorial we're going to:</p>
<ul>
<li>We’ll learn how break down a UI into React components</li>
<li>Learn how to work with state using the Context API</li>
<li>Learn about actions, reducers, and the dispatch function </li>
</ul>
<p>And I’ll give you some challenges which you can try at the end!</p>
<h2 id="heading-this-is-what-well-build">This is what we'll build:</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screenshot-2021-03-07-at-09.20.33.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The user can:</p>
<ul>
<li>Add expenses which have a name and a cost</li>
<li>Remove expenses</li>
<li>View how much of their budget is remaining</li>
<li>View how much they've spent so far </li>
<li>(Challenge) Edit budget </li>
<li>(Challenge) Search expenses</li>
</ul>
<h2 id="heading-video-walkthrough">Video Walkthrough</h2>
<p><a target="_blank" href="https://youtu.be/aeYxBd1it7I">Heres a video walkthrough if you want to supplement your reading (on YouTube)</a></p>
<h2 id="heading-source-code">Source Code</h2>
<p>Finally, in case you get lost while following along, <a target="_blank" href="https://github.com/chrisblakely01/react-budget-app">you can grab the finished code here (on GitHub)</a>.</p>
<p>Let's Go!</p>
<h2 id="heading-how-to-setup-a-react-project">How to Setup a React Project</h2>
<p>The first thing we need to do is setup a React project. For this we'll use <code>create-react-app</code>. </p>
<p>Fire up a terminal and type:</p>
<p><code>npx create-react-app budget-tracker</code> </p>
<p>When that's finished doing its thing we're going to install Bootstrap. This will give us ready-made styles we can use instead of having to create our own in CSS. </p>
<p>In the same terminal, change to your working directory, and install Bootstrap:</p>
<pre><code>cd budget-tracker
npm i bootstrap
</code></pre><p>Next we're going to install a package that allows us to generate IDs. We'll be using IDs to identify each expense in the list, so this is important.</p>
<p>Run the following command in your project directory:</p>
<pre><code>npm i uuid
</code></pre><p>The last package we need to install gives us some icons to use, which saves us from having to create them ourselves.</p>
<p>Run the following command in your project directory:</p>
<pre><code>npm i react-icons
</code></pre><p>Now open up the project in VS Code (or whatever IDE you use). You should see some stuff appear in the project tree (this is our empty React project). </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screenshot-2021-03-07-at-09.37.55-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You can ignore most of this, as we'll be creating our own components. Open up App.js, delete everything, and add the following:</p>
<pre><code class="lang-jsx"><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> <span class="hljs-string">'bootstrap/dist/css/bootstrap.min.css'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Hello React!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>What this does:</p>
<ul>
<li>Imports the bootstrap CSS into our project</li>
<li>Creates a component that displays "Hello React!" with paragraph tags</li>
<li>Exports this component so other components can use it</li>
</ul>
<p>Next we'll fire up the app and make sure everything is working as it should. Open a terminal (either in VS Code or otherwise) and start the app by typing the following:</p>
<pre><code>npm start
</code></pre><p>All being well, the app should start and open in a browser:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screenshot-2021-03-07-at-09.45.18.png" alt="Image" width="600" height="400" loading="lazy">
<em>The text "Hello React" should appear on the page. This means your app is working!</em></p>
<p>Success! Now we're ready to start building out our React components.</p>
<h2 id="heading-how-to-put-the-ui-components-in-place">How to Put the UI Components in Place</h2>
<p>One approach to building apps is to start by putting the UI components in place with some dummy data. This usually helps with visualising what state objects are needed, and usually means less rework later on. </p>
<p>With that in mind we're going to put our UI components in place starting at the top and working down. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screenshot-2021-03-07-at-10.04.55.png" alt="Image" width="600" height="400" loading="lazy">
<em>We'll add a title, then add a new component for each of the "boxes" shown. We'll add some dummy data just to get things displaying correctly</em></p>
<h3 id="heading-how-to-create-the-budget-component">How to Create the Budget Component</h3>
<p>Jump into the code, in the <strong>src</strong> folder, create a new folder called <strong>components.</strong> Within this, create a file called <strong>Budget.js.</strong> Your project structure should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screenshot-2021-03-07-at-10.13.37.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Open up <strong>Budget.js</strong> and add the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> Budget = <span class="hljs-function">() =&gt;</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">'alert alert-secondary'</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Budget: £2000<span class="hljs-tag">&lt;/<span class="hljs-name">span</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> Budget;
</code></pre>
<p>What we're doing:</p>
<ul>
<li>Creating a new component called <strong>Budget</strong> (line 3)</li>
<li>Using the <strong>Bootstrap Alert</strong> classes to gives us a nice gray background (line 5)</li>
<li>Adding some text and hard coding a value (line 6)</li>
</ul>
<h3 id="heading-how-to-create-the-remaining-component">How to Create the <code>Remaining</code> Component</h3>
<p>Next we'll create the <strong><code>Remaining</code></strong> component, which shows how much budget the user has left.</p>
<p>Create a new file under <strong>src/components</strong> called <strong>Remaining.js</strong>. Open it up and add the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> Remaining = <span class="hljs-function">() =&gt;</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">'alert alert-success'</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Remaining: £1000<span class="hljs-tag">&lt;/<span class="hljs-name">span</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> Remaining;
</code></pre>
<p>What we're doing:</p>
<ul>
<li>Creating a new component called <strong>Remaining</strong> (line 3)</li>
<li>Using the <strong>Bootstrap Alert</strong> classes to gives us a green background (line 5)</li>
<li>Adding some text and hard coding a value (line 6)</li>
<li>Adding Spent so Far</li>
</ul>
<p>Lastly, we'll create the <strong>Spent so Far</strong> component, which shows how much the user has spent so far.</p>
<p>Create a new file under <strong>src/components</strong> called <strong>ExpenseTotal.js</strong>. Open it up and add the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> ExpenseTotal = <span class="hljs-function">() =&gt;</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">'alert alert-primary'</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Spent so far: £1000<span class="hljs-tag">&lt;/<span class="hljs-name">span</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> ExpenseTotal;
</code></pre>
<p>What we're doing:</p>
<ul>
<li>Creating a new component called <strong>ExpenseTotal</strong> (line 3)</li>
<li>Using the <strong>Bootstrap Alert</strong> classes to gives us a blue background (line 5)</li>
<li>Adding some text and hard coding a value (line 6)</li>
</ul>
<h3 id="heading-how-to-add-a-title-and-render-our-components">How to Add a Title and Render our Components</h3>
<p>At this point you might be thinking, "these components all look the same, what gives?!". This is true, although remember we're just adding some hard coded data for now. Later, each component will do different things to display the data dynamically.</p>
<p>Now we've created our components, we need to render them in <strong>App.js.</strong> Open App.js and add the following:</p>
<pre><code class="lang-jsx"><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> <span class="hljs-string">'bootstrap/dist/css/bootstrap.min.css'</span>;
<span class="hljs-keyword">import</span> Budget <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Budget'</span>;
<span class="hljs-keyword">import</span> Remaining <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Remaining'</span>;
<span class="hljs-keyword">import</span> ExpenseTotal <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/ExpenseTotal'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</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">'container'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'mt-3'</span>&gt;</span>My Budget Planner<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'row mt-3'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'col-sm'</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Budget</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">'col-sm'</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Remaining</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">'col-sm'</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">ExpenseTotal</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>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>What we're doing:</p>
<ul>
<li>Importing our different components (lines 3-5)</li>
<li>Adding a bootstrap container that helps us center our App on the page (line 9)</li>
<li>Adding a title (line 9)</li>
<li>Adding a Bootstrap row (line 10)</li>
<li>Adding a column within the row for each of our components so far (lines 12-20)</li>
</ul>
<p>Now if you run the app, you should see the title, and our components rendered on the page!</p>
<h3 id="heading-how-to-create-the-expense-list-component">How to Create the Expense List Component</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screenshot-2021-03-07-at-10.31.44.png" alt="Image" width="600" height="400" loading="lazy">
<em>The expenses list shows the expenses the user has added so far, displaying the Name, cost, and a delete button for each</em></p>
<p>Next we'll build the <strong>ExpenseList</strong> component. This component will be in charge of taking a list of expenses, and rendering an <strong>ExpenseItem</strong> component for each item. </p>
<p>We'll add some dummy data, to make sure our UI looks good and things are working as intended. Later, this stuff will come from context.</p>
<p>Start by creating a new file under <strong>src/components</strong> called <strong>ExpenseList.js</strong>. Open up ExpenseList.js and add the following:</p>
<pre><code class="lang-jsx"><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> ExpenseItem <span class="hljs-keyword">from</span> <span class="hljs-string">'./ExpenseItem'</span>;

<span class="hljs-keyword">const</span> ExpenseList = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> expenses = [
        { <span class="hljs-attr">id</span>: <span class="hljs-number">12</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'shopping'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">40</span> },
        { <span class="hljs-attr">id</span>: <span class="hljs-number">13</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'holiday'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">400</span> },
        { <span class="hljs-attr">id</span>: <span class="hljs-number">14</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'car service'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">50</span> },
    ];

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'list-group'</span>&gt;</span>
            {expenses.map((expense) =&gt; (
                <span class="hljs-tag">&lt;<span class="hljs-name">ExpenseItem</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{expense.id}</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{expense.name}</span> <span class="hljs-attr">cost</span>=<span class="hljs-string">{expense.cost}</span> /&gt;</span>
            ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ExpenseList
</code></pre>
<p>What we're doing:</p>
<ul>
<li>Adding a dummy list of expenses. For each expense we need an ID, a name, and a cost. Later, we'll take this list from context (line 4)</li>
<li>Creating a list (line 11)</li>
<li>Using the map function to iterate over the expenses and displaying an ExpenseItem component (we haven't created this yet! Line 12)</li>
<li>Passing the ID, name, and cost to the ExpenseItem component as props</li>
</ul>
<h3 id="heading-how-to-create-the-expense-item-component">How to Create the Expense Item Component</h3>
<p>Now we've created a component to hold our list, we need a component to render each item. Create a new file in the <strong>src/components</strong> folder called <strong>ExpenseItem.js.</strong> Open it up and add the following:</p>
<pre><code class="lang-jsx"><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> { TiDelete } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-icons/ti'</span>;

<span class="hljs-keyword">const</span> ExpenseItem = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'list-group-item d-flex justify-content-between align-items-center'</span>&gt;</span>
            {props.name}
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'badge badge-primary badge-pill mr-3'</span>&gt;</span>
                    £{props.cost}
                <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">TiDelete</span> <span class="hljs-attr">size</span>=<span class="hljs-string">'1.5em'</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">TiDelete</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">li</span>&gt;</span></span>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ExpenseItem;
</code></pre>
<p>What we're doing:</p>
<ul>
<li>Creating a list item (line 6)</li>
<li>Rendering the name of the expense, which we get from props (line 7)</li>
<li>Rendering the cost of the expense, which we also get from props</li>
<li>We're displaying a DeleteIcon (line 12) which we get from react-icons package (line 2)</li>
</ul>
<h3 id="heading-how-to-render-the-expenselist-component">How to Render the ExpenseList Component</h3>
<p>Now we've created our components, we just have to render ExpenseList in App.js. Open up App.js and update it with the following:</p>
<pre><code class="lang-jsx"><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> <span class="hljs-string">'bootstrap/dist/css/bootstrap.min.css'</span>;
<span class="hljs-keyword">import</span> Budget <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Budget'</span>;
<span class="hljs-keyword">import</span> Remaining <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Remaining'</span>;
<span class="hljs-keyword">import</span> ExpenseTotal <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/ExpenseTotal'</span>;
<span class="hljs-keyword">import</span> ExpenseList <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/ExpenseList'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</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">'container'</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'mt-3'</span>&gt;</span>My Budget Planner<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'row mt-3'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Budget</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">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Remaining</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">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">ExpenseTotal</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">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'mt-3'</span>&gt;</span>Expenses<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'row mt-3'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">ExpenseList</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>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>What's new:</p>
<ul>
<li>We imported our ExpenseList (line 6)</li>
<li>Added a new Bootstrap row (line 24)</li>
<li>Rendered our ExpenseList (line 26)</li>
</ul>
<p>Now if you save/run the App, you'll see the Expenses list has appeared!</p>
<h3 id="heading-how-to-create-the-add-expense-form-component">How to create the "Add Expense" form component</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screenshot-2021-03-08-at-07.28.29.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Our UI components are nearly complete! The last component we need is the "Add Expense" form component, which lets users add new expenses. We'll put the UI components for the form in place first, then come back later and add the fancy stuff.</p>
<p>Create a new file in <strong>src/components</strong> called <strong>AddExpenseForm.js</strong>. Fire this up and add the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> AddExpenseForm = <span class="hljs-function">() =&gt;</span> {

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'row'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">'name'</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                        <span class="hljs-attr">required</span>=<span class="hljs-string">'required'</span>
                        <span class="hljs-attr">type</span>=<span class="hljs-string">'text'</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">'form-control'</span>
                        <span class="hljs-attr">id</span>=<span class="hljs-string">'name'</span>
                    &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">input</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">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">'cost'</span>&gt;</span>Cost<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                        <span class="hljs-attr">required</span>=<span class="hljs-string">'required'</span>
                        <span class="hljs-attr">type</span>=<span class="hljs-string">'text'</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">'form-control'</span>
                        <span class="hljs-attr">id</span>=<span class="hljs-string">'cost'</span>
                    &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">input</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> <span class="hljs-attr">className</span>=<span class="hljs-string">'row'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'col-sm'</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">className</span>=<span class="hljs-string">'btn btn-primary mt-3'</span>&gt;</span>
                        Save
                    <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>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AddExpenseForm;
</code></pre>
<p>What we're doing:</p>
<ul>
<li>Adding our form tags (line 6)</li>
<li>Adding a label/input for our <strong>name</strong> field (line 9)</li>
<li>Adding a label/input for our <strong>cost</strong> field (line 18)</li>
<li>Adding a button to submit the form (line 30)</li>
</ul>
<h3 id="heading-how-to-render-the-addexpenseform-component">How to Render the AddExpenseForm component</h3>
<p>Finally in App.js, we have to render our new component. Update App.js with the following:</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> <span class="hljs-string">'bootstrap/dist/css/bootstrap.min.css'</span>;
<span class="hljs-keyword">import</span> Budget <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Budget'</span>;
<span class="hljs-keyword">import</span> Remaining <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Remaining'</span>;
<span class="hljs-keyword">import</span> ExpenseTotal <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/ExpenseTotal'</span>;
<span class="hljs-keyword">import</span> ExpenseList <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/ExpenseList'</span>;
<span class="hljs-keyword">import</span> AddExpenseForm <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/AddExpenseForm'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</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">'container'</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'mt-3'</span>&gt;</span>My Budget Planner<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'row mt-3'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Budget</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">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Remaining</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">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">ExpenseTotal</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">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'mt-3'</span>&gt;</span>Expenses<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'row mt-3'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">ExpenseList</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">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'mt-3'</span>&gt;</span>Add Expense<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'row mt-3'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">AddExpenseForm</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>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre><p>What's changed:</p>
<ul>
<li>Imported the AddExpenseForm (line 7)</li>
<li>Rendered the AddExpenseForm (line 33)</li>
</ul>
<h2 id="heading-how-to-add-the-context-api">How to Add the Context API</h2>
<p>The Context API is what we'll use to store our global state. It's already part of the React library so no need to import/install anything else.</p>
<p>Start by creating a new folder in the <strong>src</strong> folder called <strong>context.</strong> Within this folder create a new file called <strong>AppContext.js.</strong></p>
<h3 id="heading-how-to-create-the-initial-state">How to Create the Initial State</h3>
<p>The first thing our context needs to work is an initial state. This indicates the "shape" of our state (in other words, what properties and data we have) and can be used to initialise the app with data from an API call, for example.</p>
<p>For now we'll just add some initial values. In AppContext.js, add the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> initialState = {
    <span class="hljs-attr">budget</span>: <span class="hljs-number">2000</span>,
    <span class="hljs-attr">expenses</span>: [
        { <span class="hljs-attr">id</span>: <span class="hljs-number">12</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'shopping'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">40</span> },
        { <span class="hljs-attr">id</span>: <span class="hljs-number">13</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'holiday'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">400</span> },
        { <span class="hljs-attr">id</span>: <span class="hljs-number">14</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'car service'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">50</span> },
    ],
};
</code></pre>
<ul>
<li>We're adding an initial budget</li>
<li>We're adding a dummy list of expenses</li>
</ul>
<blockquote>
<p>NOTE: the intialState properties do not need to have values, they can be set to empty strings, empty arrays, and so on. We're adding data for visual purposes</p>
</blockquote>
<h3 id="heading-how-to-create-the-appcontext">How to Create the AppContext</h3>
<p>Next we'll create the AppContext. This is the thing our components import and use to get the state. </p>
<p>Update AppContext.js with the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> initialState = {
    <span class="hljs-attr">budget</span>: <span class="hljs-number">2000</span>,
    <span class="hljs-attr">expenses</span>: [
        { <span class="hljs-attr">id</span>: <span class="hljs-number">12</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'shopping'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">40</span> },
        { <span class="hljs-attr">id</span>: <span class="hljs-number">13</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'holiday'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">400</span> },
        { <span class="hljs-attr">id</span>: <span class="hljs-number">14</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'car service'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">50</span> },
    ],
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> AppContext = createContext();
</code></pre>
<p>All we've done is added a call to createContext at line (11) - thats our context object created! </p>
<h3 id="heading-how-to-create-the-appprovider">How to Create the AppProvider</h3>
<p>The provider is a component that wraps the components which we want to pass the state to. We use it in conjunction with the useReducer hook to actually store the global state.</p>
<p>Update the AppContext.js file like so:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> initialState = {
    <span class="hljs-attr">budget</span>: <span class="hljs-number">2000</span>,
    <span class="hljs-attr">expenses</span>: [
        { <span class="hljs-attr">id</span>: <span class="hljs-number">12</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'shopping'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">40</span> },
        { <span class="hljs-attr">id</span>: <span class="hljs-number">13</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'holiday'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">400</span> },
        { <span class="hljs-attr">id</span>: <span class="hljs-number">14</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'car service'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">50</span> },
    ],
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> AppContext = createContext();

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> AppProvider = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> [state, dispatch] = useReducer(AppReducer, initialState);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AppContext.Provider</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span>
                <span class="hljs-attr">budget:</span> <span class="hljs-attr">state.budget</span>,
                <span class="hljs-attr">expenses:</span> <span class="hljs-attr">state.expenses</span>,
                <span class="hljs-attr">dispatch</span>,
            }}
        &gt;</span>
            {props.children}
        <span class="hljs-tag">&lt;/<span class="hljs-name">AppContext.Provider</span>&gt;</span></span>
    );
};
</code></pre>
<p>What we're doing:</p>
<ul>
<li>Creating our Provider component (line 12)</li>
<li>Setting up the useReducer hook which will hold our state, and allow us to update the state via dispatch (NOTE we haven't created the AppReducer yet! Line 13)</li>
<li>We're returning <strong>AppContext.Provider.</strong> This has a <strong>value</strong> prop which contains the data which we allow our components to see and have access to, as well as the dispatch function that lets us update the state by dispatching actions (line 16)</li>
</ul>
<h3 id="heading-how-to-create-the-appreducer">How to Create the AppReducer</h3>
<p>Next we’ll create the AppReducer. The reducer is in charge of creating the new global state object, based on an action type and a payload. </p>
<p>Update AppContext.js with the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> AppReducer = <span class="hljs-function">(<span class="hljs-params">state, action</span>) =&gt;</span> {
    <span class="hljs-keyword">switch</span> (action.type) {
        <span class="hljs-attr">default</span>:
            <span class="hljs-keyword">return</span> state;
    }
};

<span class="hljs-keyword">const</span> initialState = {
    <span class="hljs-attr">budget</span>: <span class="hljs-number">2000</span>,
    <span class="hljs-attr">expenses</span>: [
        { <span class="hljs-attr">id</span>: <span class="hljs-number">12</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'shopping'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">40</span> },
        { <span class="hljs-attr">id</span>: <span class="hljs-number">13</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'holiday'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">400</span> },
        { <span class="hljs-attr">id</span>: <span class="hljs-number">14</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'car service'</span>, <span class="hljs-attr">cost</span>: <span class="hljs-number">50</span> },
    ],
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> AppContext = createContext();

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> AppProvider = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> [state, dispatch] = useReducer(AppReducer, initialState);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AppContext.Provider</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span>
                <span class="hljs-attr">budget:</span> <span class="hljs-attr">state.budget</span>,
                <span class="hljs-attr">expenses:</span> <span class="hljs-attr">state.expenses</span>,
                <span class="hljs-attr">dispatch</span>,
            }}
        &gt;</span>
            {props.children}
        <span class="hljs-tag">&lt;/<span class="hljs-name">AppContext.Provider</span>&gt;</span></span>
    );
};
</code></pre>
<p>What we're doing:</p>
<ul>
<li>Creating a function which accepts the current state, and an action (line 1)</li>
<li>We use a switch based on the action.type to decide how to update the state (line 2)</li>
<li>For now since we’re just getting things set up we’re just going to return the default state, and add actions later as we need them (line 3)</li>
</ul>
<p>And thats it! Our global state is now set up and ready to go. </p>
<h2 id="heading-how-to-link-appcontext-to-our-app">How to Link AppContext to our App</h2>
<p>The next step is to link our AppContext to our App component. We do this by wrapping the components which we want to pass the state to with the AppProvider.</p>
<p>Jump back into App.js and update the following:</p>
<pre><code class="lang-jsx"><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> <span class="hljs-string">'bootstrap/dist/css/bootstrap.min.css'</span>;
<span class="hljs-keyword">import</span> Budget <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Budget'</span>;
<span class="hljs-keyword">import</span> Remaining <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Remaining'</span>;
<span class="hljs-keyword">import</span> ExpenseTotal <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/ExpenseTotal'</span>;
<span class="hljs-keyword">import</span> ExpenseList <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/ExpenseList'</span>;
<span class="hljs-keyword">import</span> AddExpenseForm <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/AddExpenseForm'</span>;
<span class="hljs-keyword">import</span> { AppProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'./context/AppContext'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AppProvider</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'container'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'mt-3'</span>&gt;</span>My Budget Planner<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'row mt-3'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'col-sm'</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Budget</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">'col-sm'</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Remaining</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">'col-sm'</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">ExpenseTotal</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">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'mt-3'</span>&gt;</span>Expenses<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'row mt-3'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'col-sm'</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">ExpenseList</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">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'mt-3'</span>&gt;</span>Add Expense<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'row mt-3'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'col-sm'</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">AddExpenseForm</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 class="hljs-tag">&lt;/<span class="hljs-name">AppProvider</span>&gt;</span></span>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>What's changed:</p>
<ul>
<li>Imported our <strong>AppProvider</strong> (line 8)</li>
<li>Nested our components in the AppProvider element (lines 12 / lines 39)</li>
</ul>
<p>Now that our components are nested within the AppProvider, they have access to <strong>value</strong> object that the AppProvider exposes. </p>
<h2 id="heading-how-to-connect-our-components-to-appcontext">How to Connect our Components to AppContext</h2>
<h3 id="heading-how-to-render-budget-from-context">How to Render Budget from Context</h3>
<p>Now we can start pulling global state values into our components. We'll start with the budget, so jump into <strong>Budget.js</strong> and add the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { AppContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'../context/AppContext'</span>;

<span class="hljs-keyword">const</span> Budget = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { budget } = useContext(AppContext);

    <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">'alert alert-secondary'</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Budget: £{budget}<span class="hljs-tag">&lt;/<span class="hljs-name">span</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> Budget;
</code></pre>
<p>What we're doing:</p>
<ul>
<li>We have to import <strong>AppContext</strong> from our Context (line 2)</li>
<li>We import the <strong>useContext</strong> hook, and pass our AppContext to it -  this is how a component connects to the context in order to get values from global state</li>
<li>We use <strong>destructuring</strong> to get the <strong>budget</strong> from context (line 5)</li>
<li>We're rendering the budget in our JSX (line 9)</li>
</ul>
<p>Now if you change the budget in AppContext and reload your browser, you will see the budget updates on the UI. This means our component is successfully pulling data from our context. Success! </p>
<h3 id="heading-how-to-render-expenses-from-context">How to Render Expenses from Context</h3>
<p>Now we can do something similar with the expense list. Open up <strong>ExpenseList.js</strong> and update it with the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ExpenseItem <span class="hljs-keyword">from</span> <span class="hljs-string">'./ExpenseItem'</span>;
<span class="hljs-keyword">import</span> { AppContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'../context/AppContext'</span>;

<span class="hljs-keyword">const</span> ExpenseList = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { expenses } = useContext(AppContext);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'list-group'</span>&gt;</span>
            {expenses.map((expense) =&gt; (
                <span class="hljs-tag">&lt;<span class="hljs-name">ExpenseItem</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{expense.id}</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{expense.name}</span> <span class="hljs-attr">cost</span>=<span class="hljs-string">{expense.cost}</span> /&gt;</span>
            ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ExpenseList;
</code></pre>
<p>What we're doing:</p>
<ul>
<li>Importing our AppContext and useContext hook like before </li>
<li>We've removed the dummy list of expenses</li>
<li>We've replaced the dummy list with the expenses list we store in context</li>
</ul>
<p>Since we've already done the work to render the list of expenses, we don't have to do anything else! Refresh the browser and you'll see the list now comes from context rather than the dummy list.</p>
<p>Remember we exported expenses as part of the value object in the provider. Any component wrapped in the provider can get access to this value object, and use destructuring to get the specific value it needs.</p>
<h3 id="heading-how-to-add-a-new-expense-capturing-form-values">How to Add a New Expense - Capturing Form Values</h3>
<p>So far we've looked at how to get values from state, next we'll look at how we can dispatch actions and update the state.</p>
<p>Before we do that, we need to know the <strong>name</strong> and the <strong>cost</strong> of the new expense that the user has entered. Jump into AddExpenseForm.js and add the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> AddExpenseForm = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">''</span>);
    <span class="hljs-keyword">const</span> [cost, setCost] = useState(<span class="hljs-string">''</span>);

    <span class="hljs-keyword">const</span> onSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {

    };

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{onSubmit}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'row'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">'name'</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                        <span class="hljs-attr">required</span>=<span class="hljs-string">'required'</span>
                        <span class="hljs-attr">type</span>=<span class="hljs-string">'text'</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">'form-control'</span>
                        <span class="hljs-attr">id</span>=<span class="hljs-string">'name'</span>
                        <span class="hljs-attr">value</span>=<span class="hljs-string">{name}</span>
                        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setName(event.target.value)}
                    &gt;<span class="hljs-tag">&lt;/<span class="hljs-name">input</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">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">'cost'</span>&gt;</span>Cost<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                        <span class="hljs-attr">required</span>=<span class="hljs-string">'required'</span>
                        <span class="hljs-attr">type</span>=<span class="hljs-string">'text'</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">'form-control'</span>
                        <span class="hljs-attr">id</span>=<span class="hljs-string">'cost'</span>
                        <span class="hljs-attr">value</span>=<span class="hljs-string">{cost}</span>
                        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setCost(event.target.value)}
                    &gt;<span class="hljs-tag">&lt;/<span class="hljs-name">input</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">'col-sm'</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">className</span>=<span class="hljs-string">'btn btn-primary mt-3'</span>&gt;</span>
                        Save
                    <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>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AddExpenseForm;
</code></pre>
<p>What we're doing:</p>
<ul>
<li>Using React to control the <strong>input values</strong>. For each input field, we have a state object (lines 7 and 8)</li>
<li>When the user types into the inputs, the corresponding state values will update (lines 25 and 36)</li>
<li>When the user clicks the button, it will call an <strong>onSubmit</strong> function. This function doesn't do anything right now, but this is where we'll dispatch the action from</li>
</ul>
<p>Now we have the form values stored in state, we can dispatch an action to update the state.</p>
<h3 id="heading-how-to-add-a-new-expense-dispatching-an-action">How to Add a New Expense - Dispatching an action</h3>
<p>Update the AddExpenseForm with the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useContext, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { AppContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'../context/AppContext'</span>;
<span class="hljs-keyword">import</span> { v4 <span class="hljs-keyword">as</span> uuidv4 } <span class="hljs-keyword">from</span> <span class="hljs-string">'uuid'</span>;

<span class="hljs-keyword">const</span> AddExpenseForm = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { dispatch } = useContext(AppContext);

    <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">''</span>);
    <span class="hljs-keyword">const</span> [cost, setCost] = useState(<span class="hljs-string">''</span>);

    <span class="hljs-keyword">const</span> onSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        event.preventDefault();

        <span class="hljs-keyword">const</span> expense = {
            <span class="hljs-attr">id</span>: uuidv4(),
            <span class="hljs-attr">name</span>: name,
            <span class="hljs-attr">cost</span>: <span class="hljs-built_in">parseInt</span>(cost),
        };

        dispatch({
            <span class="hljs-attr">type</span>: <span class="hljs-string">'ADD_EXPENSE'</span>,
            <span class="hljs-attr">payload</span>: expense,
        });
    };

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{onSubmit}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'row'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">'name'</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                        <span class="hljs-attr">required</span>=<span class="hljs-string">'required'</span>
                        <span class="hljs-attr">type</span>=<span class="hljs-string">'text'</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">'form-control'</span>
                        <span class="hljs-attr">id</span>=<span class="hljs-string">'name'</span>
                        <span class="hljs-attr">value</span>=<span class="hljs-string">{name}</span>
                        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setName(event.target.value)}
                    &gt;<span class="hljs-tag">&lt;/<span class="hljs-name">input</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">'col-sm'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">'cost'</span>&gt;</span>Cost<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                        <span class="hljs-attr">required</span>=<span class="hljs-string">'required'</span>
                        <span class="hljs-attr">type</span>=<span class="hljs-string">'text'</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">'form-control'</span>
                        <span class="hljs-attr">id</span>=<span class="hljs-string">'cost'</span>
                        <span class="hljs-attr">value</span>=<span class="hljs-string">{cost}</span>
                        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setCost(event.target.value)}
                    &gt;<span class="hljs-tag">&lt;/<span class="hljs-name">input</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">'col-sm'</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">className</span>=<span class="hljs-string">'btn btn-primary mt-3'</span>&gt;</span>
                        Save
                    <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>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AddExpenseForm;
</code></pre>
<p>What we're doing:</p>
<ul>
<li>Importing AppContext and useContext as usual </li>
<li>Getting <strong>dispatch</strong> from our global state (line 6)</li>
<li>Creating an <strong>expense object,</strong> containing the name and the cost. This is what will get dispatched as the payload, and what we'll use to update the state. We're also using the uuid package we imported earlier to create an ID. This is used to identify a given expense (line 14).</li>
<li>We're dispatching an <strong>action</strong>, with a type and our payload. The type tells the reducer how to update the state, which we'll see in a minute (line 20)</li>
</ul>
<h3 id="heading-how-to-add-a-new-expense-updating-the-reducer">How to Add a New Expense - Updating the reducer</h3>
<p>That's it from the component side. You'll notice if you run this in the browser, nothing happens. Thats because we haven't updated our reducer to handle the action and update the state. </p>
<p>Jump into <strong>AppContext.js</strong> and update the <strong>reducer</strong> function with the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> AppReducer = <span class="hljs-function">(<span class="hljs-params">state, action</span>) =&gt;</span> {
    <span class="hljs-keyword">switch</span> (action.type) {
        <span class="hljs-keyword">case</span> <span class="hljs-string">'ADD_EXPENSE'</span>:
            <span class="hljs-keyword">return</span> {
                ...state,
                <span class="hljs-attr">expenses</span>: [...state.expenses, action.payload],
            };
        <span class="hljs-keyword">default</span>:
            <span class="hljs-keyword">return</span> state;
    }
};
</code></pre>
<p>What we're doing:</p>
<ul>
<li>We're checking the type of the action (which we get from the action variable) (line 2)</li>
<li>Adding a new case to the switch statement called "ADD_EXPENSE" (line 3)</li>
<li>Returning a new state object with the new expense taking from the payload (which we get from the action variable) (line 4)</li>
</ul>
<blockquote>
<p>When we return something from a case statement, the reducer automatically updates the state and re-renders the components, almost like magic.</p>
</blockquote>
<p>Now if you run the code, and add a new expense, you can see it gets added to the expense list!</p>
<h3 id="heading-how-to-calculate-spent-so-far">How to Calculate <code>spent so far</code></h3>
<p>The next thing we'll look at is calculating how much the user has spent so far. To do this, we'll take a total of all the expenses the user has spent and display it on the UI.</p>
<p>Open up <strong>ExpenseTotal.js</strong>  and update it with the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { AppContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'../context/AppContext'</span>;

<span class="hljs-keyword">const</span> ExpenseTotal = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { expenses } = useContext(AppContext);

    <span class="hljs-keyword">const</span> totalExpenses = expenses.reduce(<span class="hljs-function">(<span class="hljs-params">total, item</span>) =&gt;</span> {
        <span class="hljs-keyword">return</span> (total += item.cost);
    }, <span class="hljs-number">0</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">'alert alert-primary'</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Spent so far: £{totalExpenses}<span class="hljs-tag">&lt;/<span class="hljs-name">span</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> ExpenseTotal;
</code></pre>
<p>What we're doing:</p>
<ul>
<li>importing our useContext and AppContext as usual </li>
<li>Taking the expenses from state (line 5)</li>
<li>Using the reduce function to get a total of all the costs and assigning this to a variable (line 7)</li>
<li>Displaying the variable in our JSX (line 13)</li>
</ul>
<p>Now whenever the user adds an expense, this causes the state to update, which will cause all components connected to the context to re-render and update themselves with new values.</p>
<p>Go ahead and try this out in the browser.</p>
<h3 id="heading-how-to-calculate-remaining">How to Calculate <code>Remaining</code></h3>
<p>Now we'll look at calculating how much budget the user has left to spend. </p>
<p>To do this, we'll get the total costs of the expenses, and subtract it from the budget. If the user goes over budget, i.e the expenses are more than the budget, we want to display a red background (as opposed to a green background). Luckily Bootstrap gives us these nice things already.</p>
<p>Open up Remaining.js and update it with the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { AppContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'../context/AppContext'</span>;

<span class="hljs-keyword">const</span> Remaining = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { expenses, budget } = useContext(AppContext);

    <span class="hljs-keyword">const</span> totalExpenses = expenses.reduce(<span class="hljs-function">(<span class="hljs-params">total, item</span>) =&gt;</span> {
        <span class="hljs-keyword">return</span> (total = total + item.cost);
    }, <span class="hljs-number">0</span>);

    <span class="hljs-keyword">const</span> alertType = totalExpenses &gt; budget ? <span class="hljs-string">'alert-danger'</span> : <span class="hljs-string">'alert-success'</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">{</span>`<span class="hljs-attr">alert</span> ${<span class="hljs-attr">alertType</span>}`}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Remaining: £{budget - totalExpenses}<span class="hljs-tag">&lt;/<span class="hljs-name">span</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> Remaining;
</code></pre>
<p>What we're doing</p>
<ul>
<li>Importing expenses and budget from Context (line 5)</li>
<li>Getting the total cost of the expenses using the reduce function (line 7)</li>
<li>Creating a variable to store the CSS classname we want to display (depending on if the user has gone over the budget or not, line 11)</li>
<li>Using a template string to create our classes (line 14)</li>
<li>Rendering the remaining budget using a subtraction (line 15)</li>
</ul>
<p>Now if you run the code in the browser, and add a bunch of expenses until the total goes over 2000, you'll see the "Remaining" component background turns to red!</p>
<h3 id="heading-how-to-remove-an-expense">How to Remove an Expense</h3>
<p>The last thing we'll look at before getting into the challenges is to remove an expense. </p>
<p>When the user clicks the little cross beside an expense, we want to dispatch an action to remove it from state. When this happens, our ExpenseList will re-render with the removed expense.</p>
<p>Jump into ExpenseItem.js and update it with the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { TiDelete } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-icons/ti'</span>;
<span class="hljs-keyword">import</span> { AppContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'../context/AppContext'</span>;

<span class="hljs-keyword">const</span> ExpenseItem = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { dispatch } = useContext(AppContext);

    <span class="hljs-keyword">const</span> handleDeleteExpense = <span class="hljs-function">() =&gt;</span> {
        dispatch({
            <span class="hljs-attr">type</span>: <span class="hljs-string">'DELETE_EXPENSE'</span>,
            <span class="hljs-attr">payload</span>: props.id,
        });
    };

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'list-group-item d-flex justify-content-between align-items-center'</span>&gt;</span>
            {props.name}
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'badge badge-primary badge-pill mr-3'</span>&gt;</span>
                    £{props.cost}
                <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">TiDelete</span> <span class="hljs-attr">size</span>=<span class="hljs-string">'1.5em'</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleDeleteExpense}</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">TiDelete</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">li</span>&gt;</span></span>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ExpenseItem;
</code></pre>
<p>What we're doing:</p>
<ul>
<li>Importing dispatch from Context, which allows us to dispatch a delete action (line 6)</li>
<li>Creating a function that gets called when the delete icon is clicked (line 8)</li>
<li>Dispatching an action. Our action contains the type (so the reducer knows how to update the state) and the payload. In this case we're passing the ID of this expense (which we get from props when we rendered the ExpenseList) (line 9)</li>
</ul>
<p>If you try this in the browser, you'll see that nothing happens. Even though we're dispatching an action, we haven't implemented the reducer logic for this action type, so it doesn't know how to update the state.</p>
<p>Jump into AppContext.js and update the reducer function with the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> AppReducer = <span class="hljs-function">(<span class="hljs-params">state, action</span>) =&gt;</span> {
    <span class="hljs-keyword">switch</span> (action.type) {
        <span class="hljs-keyword">case</span> <span class="hljs-string">'ADD_EXPENSE'</span>:
            <span class="hljs-keyword">return</span> {
                ...state,
                <span class="hljs-attr">expenses</span>: [...state.expenses, action.payload],
            };
        <span class="hljs-keyword">case</span> <span class="hljs-string">'DELETE_EXPENSE'</span>:
            <span class="hljs-keyword">return</span> {
                ...state,
                <span class="hljs-attr">expenses</span>: state.expenses.filter(
                    <span class="hljs-function">(<span class="hljs-params">expense</span>) =&gt;</span> expense.id !== action.payload
                ),
            };
        <span class="hljs-keyword">default</span>:
            <span class="hljs-keyword">return</span> state;
    }
};
</code></pre>
<p>All we're really doing here is adding a new case statement, to handle our <strong>DELETE_EXPENSE</strong> action. We're using the filter array method to remove the expense that has the ID which we received from the payload.</p>
<p>Now if you try this, you can remove an expense by clicking the delete icon. Notice how all the other components update as well. Nice!</p>
<h2 id="heading-challenges-to-try">Challenges to Try</h2>
<p>Congrats on making it this far! Now its time for you to have a go at some challenges. Remember you can see how I've done it in the GitHub source code.</p>
<h3 id="heading-allow-the-user-to-edit-the-budget">Allow the user to edit the budget</h3>
<p>You'll notice that so far we have been using a hard coded value for the budget. Your first task is to add functionality that allows the user to edit the budget. Some tips to get started:</p>
<ul>
<li>You will need to add a text input that allows the user to enter a value for their desired budget.</li>
<li>We store the budget in state, so you will need to dispatch an action with a new TYPE and a PAYLOAD that will update the state </li>
</ul>
<h3 id="heading-allow-the-user-to-search-for-an-expense">Allow the user to search for an expense</h3>
<p>If the user has many expenses, it will be difficult to find the one they are looking for. Add a way for the user to search for the expense by name. Some tips to get started:</p>
<ul>
<li>You will need to add an input field which lets the user enter a value to search for. </li>
<li>You'll have to add something to the ExpenseList component that filters the list from context based on this search value. </li>
</ul>
<h3 id="heading-thanks-for-reading">Thanks for Reading!</h3>
<p><a target="_blank" href="https://reactbeginnerprojects.com"><img src="https://www.freecodecamp.org/news/content/images/size/w1000/2021/03/Screenshot-2021-03-10-at-08.33.56.png" alt="Screenshot-2021-03-10-at-08.33.56" width="600" height="400" loading="lazy"></a> </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Multi-Step Registration App with Animated Transitions Using the MERN Stack ]]>
                </title>
                <description>
                    <![CDATA[ In this article, we will build an amazing Multi Step Registration form with smooth animated transitions using the MERN stack (MongoDB, Express, React, and Node.js). By building this App, you will learn a lot of concepts in React and Node.js including... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-multi-step-registration-app-with-animated-transitions-using-mern-stack/</link>
                <guid isPermaLink="false">66bc54f1a30f8b3984dad861</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Yogesh Chavan ]]>
                </dc:creator>
                <pubDate>Tue, 09 Mar 2021 22:24:05 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/6044ae70a7946308b76836e2.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, we will build an amazing Multi Step Registration form with smooth animated transitions using the MERN stack (MongoDB, Express, React, and Node.js).</p>
<p>By building this App, you will learn a lot of concepts in React and Node.js including:</p>
<ul>
<li>How to manage data for multiple forms with validation for each field</li>
<li>How to retain values of forms data across routes</li>
<li>How to update progress indications for each registration step</li>
<li>How to load country-specific state and city from the API</li>
<li>How to create smooth sliding animations using a very popular framer-motion library</li>
<li>How to create Rest APIs using Express.js</li>
<li>How to implement login and registration functionality with MongoDB</li>
<li>How to store and validate passwords stored in encrypted form in MongoDB</li>
</ul>
<p>And much more.</p>
<p>We will be using React Hooks syntax for building this application in React. So if you're new to React Hooks, check out my <a target="_blank" href="https://levelup.gitconnected.com/an-introduction-to-react-hooks-50281fd961fe?source=friends_link&amp;sk=89baff89ec8bc637e7c13b7554904e54">Introduction to React Hooks</a> article to learn the basics of Hooks.</p>
<p>We will also be using a MongoDB database to store the registered user data, so make sure you install MongoDB locally by following instructions from <a target="_blank" href="https://levelup.gitconnected.com/how-to-install-mongodb-database-on-local-environment-19a8a76f1b92?source=friends_link&amp;sk=416b443bad1f86b292e4b72602cf5c9b">this article</a>.</p>
<p>Alright, let’s get started.</p>
<h2 id="heading-initial-project-setup">Initial Project Setup</h2>
<p>Create a new project using <code>create-react-app</code>:</p>
<pre><code class="lang-javascript">npx create-react-app multi-step-form-using-mern
</code></pre>
<p>Once you've created the project, delete all files from the <code>src</code> folder and create an <code>index.js</code> file and a <code>styles.scss</code> file inside the <code>src</code> folder. Also create <code>components</code>, <code>router</code>,  and <code>utils</code> folders inside the <code>src</code> folder.</p>
<p>Install the necessary dependencies like this:</p>
<pre><code class="lang-javascript">yarn add axios@<span class="hljs-number">0.21</span><span class="hljs-number">.1</span> bootstrap@<span class="hljs-number">4.6</span><span class="hljs-number">.0</span> react-bootstrap@<span class="hljs-number">1.5</span><span class="hljs-number">.0</span> country-state-city@<span class="hljs-number">2.0</span><span class="hljs-number">.0</span> framer-motion@<span class="hljs-number">3.7</span><span class="hljs-number">.0</span> node-sass@<span class="hljs-number">4.14</span><span class="hljs-number">.1</span> react-hook-form@<span class="hljs-number">6.15</span><span class="hljs-number">.4</span> react-router-dom@<span class="hljs-number">5.2</span><span class="hljs-number">.0</span> sweetalert2@<span class="hljs-number">10.15</span><span class="hljs-number">.5</span>
</code></pre>
<p>Open your <code>styles.scss</code> file and add the contents from <a target="_blank" href="https://github.com/myogeshchavan97/multi-step-form-using-mern/blob/master/src/styles.scss">here</a> inside it.</p>
<p>We'll use SCSS syntax to write CSS. So if you're new to SCSS, check out <a target="_blank" href="https://medium.com/better-programming/an-introduction-to-sass-scss-fdbda159b40?source=friends_link&amp;sk=c0846e19ddb4f53919a6abaf29032d10">my article here</a> for an introduction to it.</p>
<h2 id="heading-how-to-create-the-initial-pages">How to Create the Initial Pages</h2>
<p>Create a new file <code>Header.js</code> inside the <code>components</code> folder with the following content:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> Header = <span class="hljs-function">() =&gt;</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">h1</span>&gt;</span>Multi Step Registration<span class="hljs-tag">&lt;/<span class="hljs-name">h1</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> Header;
</code></pre>
<p>Create a new file <code>FirstStep.js</code> inside the <code>components</code> folder with the following content:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> FirstStep = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      First Step Form
    <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> FirstStep;
</code></pre>
<p>Create a new file <code>AppRouter.js</code> inside the <code>router</code> folder with the following content:</p>
<pre><code class="lang-jsx"><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> { BrowserRouter, Route, Switch } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
<span class="hljs-keyword">import</span> FirstStep <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/FirstStep'</span>;
<span class="hljs-keyword">import</span> Header <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/Header'</span>;

<span class="hljs-keyword">const</span> AppRouter = <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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Header</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">component</span>=<span class="hljs-string">{FirstStep}</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">exact</span>=<span class="hljs-string">{true}</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">BrowserRouter</span>&gt;</span></span>
);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AppRouter;
</code></pre>
<p>In this file, initially, we have added a single route for the first step.</p>
<p>If you're new to React Router, check out my free <a target="_blank" href="https://yogeshchavan1.podia.com/react-router-introduction">Introduction to React Router</a> course.</p>
<p>Now, open the <code>src/index.js</code> file and add the following content inside it:</p>
<pre><code class="lang-jsx"><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-keyword">import</span> AppRouter <span class="hljs-keyword">from</span> <span class="hljs-string">'./router/AppRouter'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'bootstrap/dist/css/bootstrap.min.css'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./styles.scss'</span>;

ReactDOM.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AppRouter</span> /&gt;</span></span>, <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>));
</code></pre>
<p>Start the application by running the <code>yarn start</code> command and you will see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/multi_initial_screen.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-add-progress-steps-in-the-header">How to Add Progress Steps in the Header</h2>
<p>Create a new file called <code>Progress.js</code> inside the <code>components</code> folder with the following content:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> Progress = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.Fragment</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"steps"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"step"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>1<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>Step 1<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">"step"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>2<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>Step 2<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">"step"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>3<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>Step 3<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 class="hljs-tag">&lt;/<span class="hljs-name">React.Fragment</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Progress;
</code></pre>
<p>and use it inside the <code>Header.js</code> file as shown below:</p>
<pre><code class="lang-jsx"><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> Progress <span class="hljs-keyword">from</span> <span class="hljs-string">'./Progress'</span>;

<span class="hljs-keyword">const</span> Header = <span class="hljs-function">() =&gt;</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">h1</span>&gt;</span>Multi Step Registration<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Progress</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> Header;
</code></pre>
<p>Now, if you check the application, you will see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/with_progress.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-create-the-first-step-form">How to Create the First Step Form</h2>
<p>Open the <code>components/FirstStep.js</code> file and replace what's in there with the following contents:</p>
<pre><code class="lang-jsx"><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> { useForm } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-hook-form'</span>;
<span class="hljs-keyword">import</span> { Form, Button } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-bootstrap'</span>;

<span class="hljs-keyword">const</span> FirstStep = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { register, handleSubmit, errors } = useForm();

  <span class="hljs-keyword">const</span> onSubmit = <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(data);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"input-form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit(onSubmit)}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6 offset-md-3"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Form.Group</span> <span class="hljs-attr">controlId</span>=<span class="hljs-string">"first_name"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Label</span>&gt;</span>First Name<span class="hljs-tag">&lt;/<span class="hljs-name">Form.Label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"first_name"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your first name"</span>
            <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"off"</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{register({</span>
              <span class="hljs-attr">required:</span> '<span class="hljs-attr">First</span> <span class="hljs-attr">name</span> <span class="hljs-attr">is</span> <span class="hljs-attr">required.</span>',
              <span class="hljs-attr">pattern:</span> {
                <span class="hljs-attr">value:</span> /^[<span class="hljs-attr">a-zA-Z</span>]+$/,
                <span class="hljs-attr">message:</span> '<span class="hljs-attr">First</span> <span class="hljs-attr">name</span> <span class="hljs-attr">should</span> <span class="hljs-attr">contain</span> <span class="hljs-attr">only</span> <span class="hljs-attr">characters.</span>'
              }
            })}
            <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">errors.first_name</span> ? '<span class="hljs-attr">input-error</span>' <span class="hljs-attr">:</span> ''}`}
          /&gt;</span>
          {errors.first_name &amp;&amp; (
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorMsg"</span>&gt;</span>{errors.first_name.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          )}
        <span class="hljs-tag">&lt;/<span class="hljs-name">Form.Group</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Form.Group</span> <span class="hljs-attr">controlId</span>=<span class="hljs-string">"last_name"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Label</span>&gt;</span>Last Name<span class="hljs-tag">&lt;/<span class="hljs-name">Form.Label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"last_name"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your last name"</span>
            <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"off"</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{register({</span>
              <span class="hljs-attr">required:</span> '<span class="hljs-attr">Last</span> <span class="hljs-attr">name</span> <span class="hljs-attr">is</span> <span class="hljs-attr">required.</span>',
              <span class="hljs-attr">pattern:</span> {
                <span class="hljs-attr">value:</span> /^[<span class="hljs-attr">a-zA-Z</span>]+$/,
                <span class="hljs-attr">message:</span> '<span class="hljs-attr">Last</span> <span class="hljs-attr">name</span> <span class="hljs-attr">should</span> <span class="hljs-attr">contain</span> <span class="hljs-attr">only</span> <span class="hljs-attr">characters.</span>'
              }
            })}
            <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">errors.last_name</span> ? '<span class="hljs-attr">input-error</span>' <span class="hljs-attr">:</span> ''}`}
          /&gt;</span>
          {errors.last_name &amp;&amp; (
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorMsg"</span>&gt;</span>{errors.last_name.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          )}
        <span class="hljs-tag">&lt;/<span class="hljs-name">Form.Group</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"primary"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</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">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Form</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> FirstStep;
</code></pre>
<p>Here, we're using a very popular <a target="_blank" href="https://react-hook-form.com/">react-hook-form</a> library to easily manage forms with validations.</p>
<p>React-hook-form makes it really easy to work with simple as well as complex forms, as we don't need to manage the state of each input field and its <code>onChange</code> handler ourselves. This makes the code cleaner and easier to understand.</p>
<p>Check out <a target="_blank" href="https://www.freecodecamp.org/news/build-forms-in-react-with-react-hook-form-library/">my article here</a> to learn about <code>react-hook-form</code> in detail.</p>
<p>As you can see in the above code, to use the <code>react-hook-form</code> library we need to first import and use the <code>useForm</code> hook.</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">const</span> { register, handleSubmit, errors } = useForm();
</code></pre>
<p>Here,</p>
<ul>
<li><code>register</code> is a function that we'll use as a <code>ref</code> provided by the <code>useForm</code> hook. We can assign it to each input field so that the <code>react-hook-form</code> can track the changes for the input field value</li>
<li><code>handleSubmit</code> is the function we can call when the form is submitted</li>
<li><code>errors</code> will contain the validation errors, if any</li>
</ul>
<p>In the above code, we have given a <code>ref</code> to each input field that we got from the <code>useForm</code> hook like this:</p>
<pre><code class="lang-js">ref={register({
  <span class="hljs-attr">required</span>: <span class="hljs-string">'First name is required.'</span>,
  <span class="hljs-attr">pattern</span>: {
    <span class="hljs-attr">value</span>: <span class="hljs-regexp">/^[a-zA-Z]+$/</span>,
    message: <span class="hljs-string">'First name should contain only characters.'</span>
  }
})}
</code></pre>
<p>Also, we added the <code>onSubmit</code> function which is passed to the <code>handleSubmit</code> function.</p>
<pre><code class="lang-js">&lt;Form className=<span class="hljs-string">"input-form"</span> onSubmit={handleSubmit(onSubmit)}&gt;
</code></pre>
<p>Note that for each input field, we have given a unique <code>name</code> which is mandatory so <code>react-hook-form</code> can track the changing data.</p>
<p>When we submit the form, the <code>handleSubmit</code> function will handle the form submission. It will send the user entered data to the <code>onSubmit</code> function which we’re logging to the console.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> onSubmit = <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {  
 <span class="hljs-built_in">console</span>.log(data);
};
</code></pre>
<p>If there are any errors, we'll display them like this:</p>
<pre><code class="lang-js">{errors.first_name &amp;&amp; (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorMsg"</span>&gt;</span>{errors.first_name.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
)}
</code></pre>
<p>The <code>errors</code> object will be automatically populated with the property name denoted by the <code>name</code> given to each input field (if there are any errors). <code>first_name</code> in the above case is the name given to the first input field.</p>
<p>Now, let's check the application's functionality:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/first_step_form.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, with very little code, we've added a responsive validation functionality to the form.</p>
<h2 id="heading-how-to-create-the-second-step-form">How to Create the Second Step Form</h2>
<p>Now, create a new file <code>SecondStep.js</code> inside the <code>components</code> folder with the following content:</p>
<pre><code class="lang-jsx"><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> { useForm } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-hook-form'</span>;
<span class="hljs-keyword">import</span> { Form, Button } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-bootstrap'</span>;

<span class="hljs-keyword">const</span> SecondStep = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { register, handleSubmit, errors } = useForm();

  <span class="hljs-keyword">const</span> onSubmit = <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(data);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"input-form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit(onSubmit)}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6 offset-md-3"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Form.Group</span> <span class="hljs-attr">controlId</span>=<span class="hljs-string">"first_name"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Label</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">Form.Label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"user_email"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your email address"</span>
            <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"off"</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{register({</span>
              <span class="hljs-attr">required:</span> '<span class="hljs-attr">Email</span> <span class="hljs-attr">is</span> <span class="hljs-attr">required.</span>',
              <span class="hljs-attr">pattern:</span> {
                <span class="hljs-attr">value:</span> /^[^@ ]+@[^@ ]+\<span class="hljs-attr">.</span>[^@ <span class="hljs-attr">.</span>]{<span class="hljs-attr">2</span>,}$/,
                <span class="hljs-attr">message:</span> '<span class="hljs-attr">Email</span> <span class="hljs-attr">is</span> <span class="hljs-attr">not</span> <span class="hljs-attr">valid.</span>'
              }
            })}
            <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">errors.user_email</span> ? '<span class="hljs-attr">input-error</span>' <span class="hljs-attr">:</span> ''}`}
          /&gt;</span>
          {errors.user_email &amp;&amp; (
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorMsg"</span>&gt;</span>{errors.user_email.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          )}
        <span class="hljs-tag">&lt;/<span class="hljs-name">Form.Group</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Form.Group</span> <span class="hljs-attr">controlId</span>=<span class="hljs-string">"password"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Label</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">Form.Label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"user_password"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Choose a password"</span>
            <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"off"</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{register({</span>
              <span class="hljs-attr">required:</span> '<span class="hljs-attr">Password</span> <span class="hljs-attr">is</span> <span class="hljs-attr">required.</span>',
              <span class="hljs-attr">minLength:</span> {
                <span class="hljs-attr">value:</span> <span class="hljs-attr">6</span>,
                <span class="hljs-attr">message:</span> '<span class="hljs-attr">Password</span> <span class="hljs-attr">should</span> <span class="hljs-attr">have</span> <span class="hljs-attr">at-least</span> <span class="hljs-attr">6</span> <span class="hljs-attr">characters.</span>'
              }
            })}
            <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">errors.user_password</span> ? '<span class="hljs-attr">input-error</span>' <span class="hljs-attr">:</span> ''}`}
          /&gt;</span>
          {errors.user_password &amp;&amp; (
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorMsg"</span>&gt;</span>{errors.user_password.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          )}
        <span class="hljs-tag">&lt;/<span class="hljs-name">Form.Group</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"primary"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</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">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Form</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> SecondStep;
</code></pre>
<p>Now, let's add another route in the <code>AppRouter.js</code> file for the <code>SecondStep</code> component.</p>
<pre><code class="lang-jsx"><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> { BrowserRouter, Route, Switch } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
<span class="hljs-keyword">import</span> FirstStep <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/FirstStep'</span>;
<span class="hljs-keyword">import</span> Header <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/Header'</span>;
<span class="hljs-keyword">import</span> SecondStep <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/SecondStep'</span>;

<span class="hljs-keyword">const</span> AppRouter = <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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Header</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">component</span>=<span class="hljs-string">{FirstStep}</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">exact</span>=<span class="hljs-string">{true}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{SecondStep}</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/second"</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">BrowserRouter</span>&gt;</span></span>
);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AppRouter;
</code></pre>
<p>Also, import the <code>SecondStep</code> component at the top of the file as shown above.</p>
<p>Now, we've added a route for the second step, let's check the application by accessing the URL  <a target="_blank" href="http://localhost:3000/second">http://localhost:3000/second</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/second_step_form.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, the functionality is working fine, but we're directly accessing the <code>/second</code> route. Instead, let's add the code to programmatically redirect from step 1 to step 2.</p>
<p>When we provide any component for the <code>Route</code> inside the <code>BrowserRouter</code>, React Router automatically passes 3 props to that component, which are:</p>
<ul>
<li>history</li>
<li>location</li>
<li>match</li>
</ul>
<p>Out of these, the <code>history</code> object contains a <code>push</code> method that we can use to redirect from one component to another.</p>
<p>So open the <code>FirstStep.js</code> file and replace the <code>onSubmit</code> function with the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> onSubmit = <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(data);
  props.history.push(<span class="hljs-string">'/second'</span>);
};
</code></pre>
<p>Here, for the <code>push</code> method, we've provided the route to which we need to redirect.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/redirection.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, when we click on the <code>Next</code> button in the first step we're redirected to the second step.</p>
<p>Now, create a new file <code>constants.js</code> inside the <code>utils</code> folder with the following content:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> BASE_API_URL = <span class="hljs-string">'http://localhost:3030'</span>;
</code></pre>
<p>Here, we're specifying our backend API's URL so we don't need to specify it in every API call. We just need to use this constant when we need to make an API call.</p>
<p>Now, let's add another route in our <code>AppRouter.js</code> file for the <code>ThirdStep</code> component.</p>
<pre><code class="lang-jsx">...
&lt;Switch&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{FirstStep}</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">exact</span>=<span class="hljs-string">{true}</span> /&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{SecondStep}</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/second"</span> /&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{ThirdStep}</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/third"</span> /&gt;</span></span>
&lt;/Switch&gt;
...
</code></pre>
<h2 id="heading-how-to-get-a-list-of-all-countries-from-the-api">How to Get a List of All Countries from the API</h2>
<p>Create a new file <code>ThirdStep.js</code> inside the <code>components</code> folder with the following content:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { Form, Button } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-bootstrap'</span>;
<span class="hljs-keyword">import</span> csc <span class="hljs-keyword">from</span> <span class="hljs-string">'country-state-city'</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> { BASE_API_URL } <span class="hljs-keyword">from</span> <span class="hljs-string">'../utils/constants'</span>;

<span class="hljs-keyword">const</span> ThirdStep = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [countries, setCountries] = useState([]);
  <span class="hljs-keyword">const</span> [states, setStates] = useState([]);
  <span class="hljs-keyword">const</span> [cities, setCities] = useState([]);
  <span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> [selectedCountry, setSelectedCountry] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [selectedState, setSelectedState] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [selectedCity, setSelectedCity] = useState(<span class="hljs-string">''</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
   <span class="hljs-keyword">const</span> getCountries = <span class="hljs-keyword">async</span> () =&gt; {
     <span class="hljs-keyword">try</span> {
       <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> csc.getAllCountries();
       <span class="hljs-built_in">console</span>.log(result);
     } <span class="hljs-keyword">catch</span> (error) {}
    };

    getCountries();
  }, []);

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (event) =&gt; {
    event.preventDefault();
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"input-form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6 offset-md-3"</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">Form</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ThirdStep;
</code></pre>
<p>In this file, we're using a <a target="_blank" href="https://www.npmjs.com/package/country-state-city">country-state-city</a> npm library to get a list of available countries, cities, and states like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> csc <span class="hljs-keyword">from</span> <span class="hljs-string">'country-state-city'</span>;
</code></pre>
<p>Then in the component, we've defined some states:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [countries, setCountries] = useState([]);
<span class="hljs-keyword">const</span> [states, setStates] = useState([]);
<span class="hljs-keyword">const</span> [cities, setCities] = useState([]);
<span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState(<span class="hljs-literal">false</span>);

<span class="hljs-keyword">const</span> [selectedCountry, setSelectedCountry] = useState(<span class="hljs-string">''</span>);
<span class="hljs-keyword">const</span> [selectedState, setSelectedState] = useState(<span class="hljs-string">''</span>);
<span class="hljs-keyword">const</span> [selectedCity, setSelectedCity] = useState(<span class="hljs-string">''</span>);
</code></pre>
<p>Here, <code>countries</code>, <code>states</code> and <code>cities</code> are declared in the state that will store the list of <code>countries</code>, <code>states</code> and <code>cities</code>, respectively, coming from the API.</p>
<p>We add another <code>isLoading</code> state to keep track of when the data is loading. <code>selectedCountry</code>, <code>selectedState</code> and <code>selectedCity</code> will contain the selected value when the user selects a particular dropdown value.</p>
<p>Then we've added a <code>useEffect</code> hook to make an API call to get the list of countries as shown below:</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
  ...
  const result = <span class="hljs-keyword">await</span> csc.getAllCountries();
  ...
}, []);
</code></pre>
<p>Here, we're calling the <code>getAllCountries</code> method of the <code>country-state-city</code> library to get a list of available countries.  </p>
<p>Note that we've passed an empty array <code>[]</code> as the second argument to the <code>useEffect</code> hook so the hook will be called only once when the component is mounted.</p>
<p>Now, open the <code>SecondStep.js</code> file and replace the <code>onSubmit</code> function with the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> onSubmit = <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(data);
  props.history.push(<span class="hljs-string">'/third'</span>);
};
</code></pre>
<p>Using this code, we can easily navigate to the <code>ThirdStep</code> component.</p>
<p>Now, let's check the application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/countries_log.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, on the component load, we're getting a list of available countries in an array of objects.</p>
<p>Each object contains an <code>isoCode</code> and <code>name</code> property that we can use in our code to display it on the screen.</p>
<p>So change the <code>useEffect</code> hook to the below code:</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> getCountries = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      setIsLoading(<span class="hljs-literal">true</span>);
      <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> csc.getAllCountries();
      <span class="hljs-keyword">let</span> allCountries = [];
      allCountries = result?.map(<span class="hljs-function">(<span class="hljs-params">{ isoCode, name }</span>) =&gt;</span> ({
        isoCode,
        name
      }));
      <span class="hljs-keyword">const</span> [{ <span class="hljs-attr">isoCode</span>: firstCountry } = {}] = allCountries;
      setCountries(allCountries);
      setSelectedCountry(firstCountry);
      setIsLoading(<span class="hljs-literal">false</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      setCountries([]);
      setIsLoading(<span class="hljs-literal">false</span>);
    }
  };

  getCountries();
}, []);
</code></pre>
<p>Here, we're first setting the <code>isLoading</code> flag to <code>true</code> to indicate that data is loading, which we will use soon.</p>
<p>Each object of the array contains many other properties like <code>phonecode</code>, <code>flag</code>, <code>currency</code> and so on, but we only want <code>isoCode</code> and <code>name</code>. So we're using the array map method to filter out only those properties, as shown below:</p>
<pre><code class="lang-js">allCountries = result?.map(<span class="hljs-function">(<span class="hljs-params">{ isoCode, name }</span>) =&gt;</span> ({
  isoCode,
  name
}));
</code></pre>
<p>Here, we're using the ES11 optional chaining operator which is denoted by the <code>?</code>. The code after the <code>?</code> will be executed only if the previous reference is not <code>undefined</code> or <code>null</code>. And as we're destructuring <code>isoCode</code> and <code>name</code>, we need the optional chaining operator.</p>
<p>The optional chaining operator is very useful in many scenarios. You can learn more about it in my <a target="_blank" href="https://modernjavascript.yogeshchavan.dev/">Mastering Modern JavaScript</a> book.</p>
<p>Now we have the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [{ <span class="hljs-attr">isoCode</span>: firstCountry } = {}] = allCountries;
setCountries(allCountries);
setSelectedCountry(firstCountry);
setIsLoading(<span class="hljs-literal">false</span>);
</code></pre>
<p>Let's understand what we're doing here.</p>
<p>Here, we've used object destructuring renaming with assignment syntax. We're destructuring the <code>isoCode</code> property from the first object of the <code>allCountries</code> array of objects and renaming the <code>isoCode</code> property to <code>firstCountry</code> just to identify that it's the first country from the list. </p>
<p>We're also assigning a default empty object so that if the <code>allCountries</code> array is empty we won't get an error.</p>
<p>In short, we are saying to take the <code>isoCode</code> property from the first object from the <code>allCountries</code> array of objects and rename it to <code>firstCountry</code> . </p>
<p>If the <code>firstCountry</code> property does not exist in the first object from the <code>allCountries</code> array, then assign a default value of empty object <code>{}</code> to the <code>firstCountry</code> variable.</p>
<p>Then we're updating the <code>selectedCountry</code> state value to the <code>firstCountry</code> value and <code>isLoading</code> state value to <code>false</code> using the below code:</p>
<pre><code class="lang-js">setSelectedCountry(firstCountry);
setIsLoading(<span class="hljs-literal">false</span>);
</code></pre>
<p>Now, in the <code>ThirdStep.js</code> file, change the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">return</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"input-form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6 offset-md-3"</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">Form</span>&gt;</span></span>
);
</code></pre>
<p>to this code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"input-form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6 offset-md-3"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Form.Group</span> <span class="hljs-attr">controlId</span>=<span class="hljs-string">"country"</span>&gt;</span>
          {isLoading &amp;&amp; (
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"loading"</span>&gt;</span>Loading countries. Please wait...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          )}
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Label</span>&gt;</span>Country<span class="hljs-tag">&lt;/<span class="hljs-name">Form.Label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
            <span class="hljs-attr">as</span>=<span class="hljs-string">"select"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"country"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{selectedCountry}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setSelectedCountry(event.target.value)}
          &gt;
            {countries.map(({ isoCode, name }) =&gt; (
              <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{isoCode}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{isoCode}</span>&gt;</span>
                {name}
              <span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
            ))}
          <span class="hljs-tag">&lt;/<span class="hljs-name">Form.Control</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Form.Group</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">Form</span>&gt;</span></span>
  );
</code></pre>
<p>We can see the list of countries populated in the dropdown.</p>
<p>Now, if you navigate to step 3, you will see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/country_populate.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, the country dropdown is correctly populated with all countries. On change of the dropdown value, the <code>selectedCountry</code> state also changes to the country code (<code>isoCode</code>) as you can see in the React dev tools.</p>
<h2 id="heading-how-to-get-a-list-of-states-from-the-api">How to Get a List of States from the API</h2>
<p>Now, let's add the code for getting a list of states based on the selected country.</p>
<p>Add the following code after the first <code>useEffect</code> hook in the <code>ThirdStep.js</code> file.</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> getStates = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> csc.getStatesOfCountry(selectedCountry);
        <span class="hljs-keyword">let</span> allStates = [];
        allStates = result?.map(<span class="hljs-function">(<span class="hljs-params">{ isoCode, name }</span>) =&gt;</span> ({
          isoCode,
          name
        }));
        <span class="hljs-built_in">console</span>.log({ allStates });
        <span class="hljs-keyword">const</span> [{ <span class="hljs-attr">isoCode</span>: firstState = <span class="hljs-string">''</span> } = {}] = allStates;
        setCities([]);
        setSelectedCity(<span class="hljs-string">''</span>);
        setStates(allStates);
        setSelectedState(firstState);
      } <span class="hljs-keyword">catch</span> (error) {
        setStates([]);
        setCities([]);
        setSelectedCity(<span class="hljs-string">''</span>);
      }
    };

    getStates();
  }, [selectedCountry]);
</code></pre>
<p>Here, we're calling the <code>getStatesOfCountry</code> method from the <code>country-state-city</code> library by passing the <code>selectedCountry</code> as the parameter. Then based on the result of the API, we're updating the respective states as shown below:</p>
<pre><code class="lang-js">setCities([]);
setSelectedCity(<span class="hljs-string">''</span>);
setStates(allStates);
setSelectedState(firstState);
</code></pre>
<p>All the country, state and city dropdowns are inter-related. If we're changing the country, we should update the state also, which we're doing in the above code.</p>
<p>Also, note that we've passed the <code>selectedCountry</code> as a second parameter to the <code>useEffect</code> hook in the dependencies array:</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
 ...
}, [selectedCountry]);
</code></pre>
<p>So this effect will only run when the <code>selectedCountry</code> state changes. This means that once we change the country dropdown, we're making an API call to get the states related to only that country and then populating the state's dropdown values.</p>
<p>Now, add the following code after the first <code>Form.Group</code> closing tag that's after the country dropdown:</p>
<pre><code class="lang-jsx">&lt;Form.Group controlId=<span class="hljs-string">"state"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Form.Label</span>&gt;</span>State<span class="hljs-tag">&lt;/<span class="hljs-name">Form.Label</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
    <span class="hljs-attr">as</span>=<span class="hljs-string">"select"</span>
    <span class="hljs-attr">name</span>=<span class="hljs-string">"state"</span>
    <span class="hljs-attr">value</span>=<span class="hljs-string">{selectedState}</span>
    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setSelectedState(event.target.value)}
  &gt;
    {states.length &gt; 0 ? (
      states.map(({ isoCode, name }) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{isoCode}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{isoCode}</span>&gt;</span>
          {name}
        <span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
      ))
    ) : (
      <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">""</span> <span class="hljs-attr">key</span>=<span class="hljs-string">""</span>&gt;</span>
        No state found
      <span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
    )}
  <span class="hljs-tag">&lt;/<span class="hljs-name">Form.Control</span>&gt;</span></span>
&lt;/Form.Group&gt;
</code></pre>
<p>Here, we're displaying the state dropdown on the screen. If there are no states for the selected country, we show a <code>No state found</code> message because there are some countries that don't have any states.</p>
<p>Now, if you check the application, you will see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/state_populate.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see above, when we change the country dropdown value, the state dropdown list is also updated based on the selected country.</p>
<h2 id="heading-how-to-get-a-list-of-cities-from-the-api">How to Get a List of Cities from the API</h2>
<p>Now, let's populate the cities based on the country and state values.</p>
<p>Add another <code>useEffect</code> hook after the second hook as shown below:</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> getCities = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> csc.getCitiesOfState(
        selectedCountry,
        selectedState
      );
      <span class="hljs-keyword">let</span> allCities = [];
      allCities = result?.map(<span class="hljs-function">(<span class="hljs-params">{ name }</span>) =&gt;</span> ({
        name
      }));
      <span class="hljs-keyword">const</span> [{ <span class="hljs-attr">name</span>: firstCity = <span class="hljs-string">''</span> } = {}] = allCities;
      setCities(allCities);
      setSelectedCity(firstCity);
    } <span class="hljs-keyword">catch</span> (error) {
      setCities([]);
    }
  };

  getCities();
}, [selectedState]);
</code></pre>
<p>Here, we're calling the <code>getCitiesOfState</code> method from the <code>country-state-city</code> library by passing the <code>selectedCountry</code> and <code>selectedState</code> as parameters. Based on the result of the API, we update the cities dropdown.</p>
<p>Now, add the following code after the second <code>Form.Group</code> closing tag that's after the state dropdown:</p>
<pre><code class="lang-jsx">&lt;Form.Group controlId=<span class="hljs-string">"city"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Form.Label</span>&gt;</span>City<span class="hljs-tag">&lt;/<span class="hljs-name">Form.Label</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
    <span class="hljs-attr">as</span>=<span class="hljs-string">"select"</span>
    <span class="hljs-attr">name</span>=<span class="hljs-string">"city"</span>
    <span class="hljs-attr">value</span>=<span class="hljs-string">{selectedCity}</span>
    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setSelectedCity(event.target.value)}
  &gt;
    {cities.length &gt; 0 ? (
      cities.map(({ name }) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{name}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{name}</span>&gt;</span>
          {name}
        <span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
      ))
    ) : (
      <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">""</span>&gt;</span>No cities found<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
    )}
  <span class="hljs-tag">&lt;/<span class="hljs-name">Form.Control</span>&gt;</span></span>
&lt;/Form.Group&gt;
</code></pre>
<p>Here, we're displaying the cities dropdown on the screen. If there are no cities for the selected state, we show a <code>No cities found</code> message because there are some states that don't have any cities.</p>
<p>Now, if you check the application, you will see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/city_populate.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see above, on change of country and state, the corresponding list of cities is populated in the cities dropdown.</p>
<p>Also, add the <code>Register</code> button after the last <code>Form.Group</code> closing tag that's after the city dropdown:</p>
<pre><code class="lang-jsx">&lt;Button variant=<span class="hljs-string">"primary"</span> type=<span class="hljs-string">"submit"</span>&gt;
  Register
&lt;/Button&gt;
</code></pre>
<p>Now, your screen will look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/last_step.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We're done creating screens for all the steps. Now let's get the step progress in the header working so it's clear which step we're currently on.</p>
<h2 id="heading-how-to-add-a-progress-indicator-in-the-header">How to Add a Progress Indicator in the Header</h2>
<p>We're showing the <code>Progress</code> component inside the <code>Header</code> component, but the <code>Progress</code> component is not mentioned in any of the <code>Route</code>s in the <code>AppRouter.js</code> file. Also, <code>Header</code> isn't mentioned in the <code>Route</code>. </p>
<p>So by default, we don't have access to the <code>history</code>, <code>location</code> and <code>match</code> props in both the <code>Header</code> and <code>Progress</code> components to identify which route we're on.</p>
<p>But there is an easy way to fix this. React Router provides a <code>withRouter</code> component which we can use in the <code>Progress</code> component so we will get access to the <code>history</code>, <code>location</code> and <code>match</code> props.</p>
<p>Open the <code>Progress.js</code> file and add import the <code>withRouter</code> component at the top of the file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { withRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
</code></pre>
<p>and change the export statement from this code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Progress;
</code></pre>
<p>to this code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> withRouter(Progress);
</code></pre>
<p>So when we pass the <code>Progress</code> component to the <code>withRouter</code> component we'll get access to the <code>history</code>, <code>location</code> and <code>match</code> props inside the <code>Progress</code> component.</p>
<p>Now, replace the <code>Progress</code> component with the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Progress = <span class="hljs-function">(<span class="hljs-params">{ location: { pathname } }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> isFirstStep = pathname === <span class="hljs-string">'/'</span>;
  <span class="hljs-keyword">const</span> isSecondStep = pathname === <span class="hljs-string">'/second'</span>;
  <span class="hljs-keyword">const</span> isThirdStep = pathname === <span class="hljs-string">'/third'</span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.Fragment</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"steps"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">isFirstStep</span> ? '<span class="hljs-attr">step</span> <span class="hljs-attr">active</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">step</span>'}`}&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>1<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>
            {isSecondStep || isThirdStep ? (
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>Step 1<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
            ) : (
              'Step 1'
            )}
          <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">{</span>`${<span class="hljs-attr">isSecondStep</span> ? '<span class="hljs-attr">step</span> <span class="hljs-attr">active</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">step</span>'}`}&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>2<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>{isThirdStep ? <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/second"</span>&gt;</span>Step 2<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span> : 'Step 2'}<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">{</span>`${<span class="hljs-attr">pathname</span> === <span class="hljs-string">'/third'</span> ? '<span class="hljs-attr">step</span> <span class="hljs-attr">active</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">step</span>'}`}&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>3<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>Step 3<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 class="hljs-tag">&lt;/<span class="hljs-name">React.Fragment</span>&gt;</span></span>
  );
};
</code></pre>
<p>Here, in the first line, we're destructuring the <code>location</code> property from the <code>props</code> object and then the <code>pathname</code> property from the <code>location</code> property in a single line like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Progress = <span class="hljs-function">(<span class="hljs-params">{ location: { pathname } }</span>) =&gt;</span> {
</code></pre>
<p>And based on which route we're on, we're adding the <code>active</code> class to each <code>step</code> div.</p>
<p>Also, import the <code>Link</code> component at the top of the file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { Link, withRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
</code></pre>
<p>Now, if you check the application, you will see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/progress_working.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, when we're on a particular step, that step number is shown as active in the progress bar with highlighted text. Then, as we navigate through the steps, the text of the previous steps is shown as a link so we can navigate back to any step to change any data.</p>
<h2 id="heading-how-to-retain-entered-data-across-routes">How to Retain Entered Data Across Routes</h2>
<p>But you will notice that, when we go to step 1 by clicking the link from step 3, the data entered in step 1 is lost.</p>
<p>This is because when we go from one route to another route, React Router completely unmounts the previous route component and mounts the next route component connected to that route. This causes all state values to be lost.</p>
<p>So let's add a way to preserve the data that's been entered when navigating to the previous step.</p>
<p>As you know, only the components connected to the routes mentioned in the <code>AppRouter.js</code> file are mounted and unmounted on the route change. But the <code>AppRouter</code> component in our case is not unmounted even when the routes change.</p>
<p>This means that the best place to store the data entered by the user is in the <code>AppRouter</code> component.</p>
<p>Let's add the <code>user</code> state,  <code>updateUser</code>, and <code>resetUser</code> functions inside the <code>AppRouter.js</code> file.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [user, setUser] = useState({});

<span class="hljs-keyword">const</span> updateUser = <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
  setUser(<span class="hljs-function">(<span class="hljs-params">prevUser</span>) =&gt;</span> ({ ...prevUser, ...data }));
};

<span class="hljs-keyword">const</span> resetUser = <span class="hljs-function">() =&gt;</span> {
  setUser({});
};
</code></pre>
<p>So we will store the user-entered data in each step in the <code>user</code> state that's an object.</p>
<p>In the <code>updateUser</code> function, we're passing data to update the <code>user</code> state. In the <code>updateUser</code> function, we're first spreading out the <code>user</code> object values using the <code>prevUser</code> variable and then spreading out the <code>data</code> object so the resulting object will be the merging of two objects.</p>
<p>To update the state, we use the updater syntax of state with implicit return syntax for the object.</p>
<p>So this code:</p>
<pre><code class="lang-js">setUser(<span class="hljs-function">(<span class="hljs-params">prevUser</span>) =&gt;</span> ({ ...prevUser, ...data }));
</code></pre>
<p>is the same as the below code:</p>
<pre><code class="lang-js">setUser(<span class="hljs-function">(<span class="hljs-params">prevUser</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> {
    ...prevUser,
    ...data
  };
});
</code></pre>
<p>As you can see above, if we want to implicitly return an object from an arrow function, we can skip the return keyword and enclose the object in round brackets.</p>
<p>This will make the code shorter and will also help you avoid typing mistakes in your code. Because of this, you will find that most React code is written using implicit return syntax.</p>
<p>So if we're in step 1 then we will pass the <code>{first_name: 'Mike', last_name: 'Jordan' }</code> as <code>data</code> and add it to the <code>user</code> state.</p>
<p>Then in step 2, if we pass <code>{user_email: 'test@example.com', user_password: 'test@123'}</code> as the <code>data</code>, then the <code>updateUser</code> function will update the <code>user</code> as shown below:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> prevUser = { <span class="hljs-attr">first_name</span>: <span class="hljs-string">'Mike'</span>, <span class="hljs-attr">last_name</span>: <span class="hljs-string">'Jordan'</span> };
<span class="hljs-keyword">const</span> data = { <span class="hljs-attr">user_email</span>: <span class="hljs-string">'test@example.com'</span>, <span class="hljs-attr">user_password</span>: <span class="hljs-string">'test@123'</span> };

<span class="hljs-keyword">const</span> result = { ...prevUser, ...data };
<span class="hljs-built_in">console</span>.log(result); <span class="hljs-comment">// { first_name: 'Mike', last_name: 'Jordan', user_email: 'test@example.com', user_password: 'test@123' }</span>
</code></pre>
<p>Now, we have created the <code>user</code> state and <code>updateUser</code> function. So we need to pass it to each route that is connected to the step so we can save the user-entered data by calling the <code>updateUser</code> function.</p>
<p>Our current routes in the <code>AppRouter.js</code> file look like this:</p>
<pre><code class="lang-js">&lt;Switch&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{FirstStep}</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">exact</span>=<span class="hljs-string">{true}</span> /&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{SecondStep}</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/second"</span> /&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{ThirdStep}</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/third"</span> /&gt;</span></span>
&lt;/Switch&gt;
</code></pre>
<p>So to pass the <code>user</code> and <code>updateUser</code> as props to the components connected to the route, we can't pass it like this:</p>
<pre><code class="lang-js">&lt;Route component={FirstStep} path=<span class="hljs-string">"/"</span> exact={<span class="hljs-literal">true</span>} user={user} updateUser={updateUser} /&gt;
</code></pre>
<p>Because this way props will be passed to the <code>Route</code> and not to the <code>FirstStep</code> component. So we need to use the following syntax:</p>
<pre><code class="lang-js">&lt;Route
  render={<span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">FirstStep</span> {<span class="hljs-attr">...props</span>} <span class="hljs-attr">user</span>=<span class="hljs-string">{user}</span> <span class="hljs-attr">updateUser</span>=<span class="hljs-string">{updateUser}</span> /&gt;</span></span>
  )}
  path=<span class="hljs-string">"/"</span>
  exact={<span class="hljs-literal">true</span>}
/&gt;
</code></pre>
<p>Here, we're using the render props pattern for passing props. This will correctly pass the props and will also not re-create the <code>FirstStep</code> component on every re-render.</p>
<p>You can check out my <a target="_blank" href="https://yogeshchavan1.podia.com/react-router-introduction">Introduction to React Router</a> course to learn more about why we need to use <code>render</code> instead of the <code>component</code> prop.</p>
<p>Now, after making this change for all the step-related routes, your routes will look like this:</p>
<pre><code class="lang-jsx">&lt;BrowserRouter&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Header</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">render</span>=<span class="hljs-string">{(props)</span> =&gt;</span> (
          <span class="hljs-tag">&lt;<span class="hljs-name">FirstStep</span> {<span class="hljs-attr">...props</span>} <span class="hljs-attr">user</span>=<span class="hljs-string">{user}</span> <span class="hljs-attr">updateUser</span>=<span class="hljs-string">{updateUser}</span> /&gt;</span>
        )}
        path="/"
        exact={true}
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span>
        <span class="hljs-attr">render</span>=<span class="hljs-string">{(props)</span> =&gt;</span> (
          <span class="hljs-tag">&lt;<span class="hljs-name">SecondStep</span> {<span class="hljs-attr">...props</span>} <span class="hljs-attr">user</span>=<span class="hljs-string">{user}</span> <span class="hljs-attr">updateUser</span>=<span class="hljs-string">{updateUser}</span> /&gt;</span>
        )}
        path="/second"
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span>
        <span class="hljs-attr">render</span>=<span class="hljs-string">{(props)</span> =&gt;</span> (
          <span class="hljs-tag">&lt;<span class="hljs-name">ThirdStep</span> {<span class="hljs-attr">...props</span>} <span class="hljs-attr">user</span>=<span class="hljs-string">{user}</span>  /&gt;</span>
        )}
        path="/third"
      /&gt;
    <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>
&lt;/BrowserRouter&gt;
</code></pre>
<p>Note that we're not passing the <code>updateUser</code> prop to the <code>ThirdStep</code> component route, because when we submit the form from step 3, we will be saving all the data directly into the database.</p>
<p>If you want you can pass the <code>updateUser</code> function to the <code>ThirdStep</code> component and save it to the state by calling the <code>updateUser</code> function (but it's not necessary).</p>
<p>Now, let's use the <code>updateUser</code> function inside these components to save the data.</p>
<p>So open the <code>FirstStep.js</code> and <code>SecondStep.js</code> files and inside the <code>onSubmit</code> handler function, and add <code>props.updateUser(data)</code> as the first statement.</p>
<pre><code class="lang-js"><span class="hljs-comment">// FirstStep.js</span>
<span class="hljs-keyword">const</span> onSubmit = <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
  props.updateUser(data);
  props.history.push(<span class="hljs-string">'/second'</span>);
};

<span class="hljs-comment">// SecondStep.js</span>
<span class="hljs-keyword">const</span> onSubmit = <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
  props.updateUser(data);
  props.history.push(<span class="hljs-string">'/third'</span>);
};
</code></pre>
<p>Now, if you check the application, you will see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/saving_to_state.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, initially the <code>AppRouter</code> component state is an empty object. But when we submit the form in each step, the state object gets updated with the user-entered data.</p>
<p>Now, let's use that data saved in the state and populate it in the respective input fields when we come back to the previous step from the next step.</p>
<p>As you know, we're using <code>react-hook-form</code> to manage the changing data of our forms in the <code>FirstStep</code> and <code>SecondStep</code> component using the <code>useForm</code> hook.</p>
<p>But the <code>useForm</code> hook also takes an optional parameter which we can use to persist the values across route changes.</p>
<p>So change the below code from the <code>FirstStep.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { register, handleSubmit, errors } = useForm();
</code></pre>
<p>to this code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { user } = props;
<span class="hljs-keyword">const</span> { register, handleSubmit, errors } = useForm({
  <span class="hljs-attr">defaultValues</span>: {
    <span class="hljs-attr">first_name</span>: user.first_name,
    <span class="hljs-attr">last_name</span>: user.last_name
  }
});
</code></pre>
<p>Here, we're destructuring the <code>user</code> prop from the props object which we're passing in the route of the <code>AppRouter.js</code> file. Then we're using the <code>defaultValues</code> property to set the value for each input field.</p>
<p>Just to remind you, <code>first_name</code>  and <code>last_name</code> are the names given to the input fields in <code>FirstStep</code> component which react-hook-form uses to track changing data.</p>
<p>Now, if you check the application, you will see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/data_retained.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, when we come back from step 2 to step 1, the data entered in step 1 is not lost. This is because we're re-setting it with the data from the <code>user</code> state when the component is mounted again on route change.</p>
<p>Now, let's add some similar code in the <code>SecondStep.js</code> file also:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { user } = props;
<span class="hljs-keyword">const</span> { register, handleSubmit, errors } = useForm({
  <span class="hljs-attr">defaultValues</span>: {
    <span class="hljs-attr">user_email</span>: user.user_email,
    <span class="hljs-attr">user_password</span>: user.user_password
  }
});
</code></pre>
<p>If you check the application, you will see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/data_retained_step2.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, when we come back from step 3 to step 2 or step 1, the data entered in step 1 and step 2 is not lost. So we have successfully preserved the data across steps.</p>
<h2 id="heading-how-to-add-animated-transitions-to-the-app">How to Add Animated Transitions to the App</h2>
<p>Now, let's add a smooth sliding animation functionality to the app.</p>
<p>To add animation, we're using the very popular <a target="_blank" href="https://www.framer.com/motion/">framer motion</a> library.</p>
<p>Framer motion makes it easy to add animation using a declarative approach in the same way that React does things.</p>
<p>So let's add animation in the <code>FirstStep</code> component.</p>
<p>Open the <code>FirstStep.js</code> file and add the import statement for the framer motion library at the top of the file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { motion } <span class="hljs-keyword">from</span> <span class="hljs-string">'framer-motion'</span>;
</code></pre>
<p>To animate any element on the page, we need to prefix it with <code>motion</code> like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Click here to animate it<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

// the above code will need to be converted to

<span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>&gt;</span>Click here to animate it<span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span>
</code></pre>
<p>Using motion as a prefix will return a React component that has specific animating capabilities added so that we can pass props to that element.</p>
<p>So inside the <code>FirstStep.js</code> file, after adding the motion prefix to the following div:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6 offset-md-3"</span>&gt;</span>
...
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>it will look like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6 offset-md-3"</span>&gt;</span>
...
<span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span>
</code></pre>
<p>Once we add a motion prefix to it, we can provide extra props to that element like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
  <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6 offset-md-3"</span>
  <span class="hljs-attr">initial</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">x:</span> '<span class="hljs-attr">-100vw</span>' }}
  <span class="hljs-attr">animate</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">x:</span> <span class="hljs-attr">0</span> }}
&gt;</span>
...
<span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span>
</code></pre>
<p>Here, we've provided an <code>initial</code> prop to specify the location from where the animation will begin. We want the entire form to be slid in from the left side so we provided the <code>x</code> value as <code>-100vw</code>. This means 100% viewport width from the left side. So the initial position of the form will be far left but not visible on the screen.</p>
<p>Then we provided the <code>animate</code> prop with an <code>x</code> value of <code>0</code> so the form will slide in from left and will come back to its original position on the page. If we provide a value of <code>10</code> for <code>x</code> then it will move to <code>10px</code> on the right side from its original position.</p>
<p>Now, your entire JSX code in the <code>FirstStep.js</code> file will look like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">return</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"input-form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit(onSubmit)}</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6 offset-md-3"</span>
      <span class="hljs-attr">initial</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">x:</span> '<span class="hljs-attr">-100vw</span>' }}
      <span class="hljs-attr">animate</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">x:</span> <span class="hljs-attr">0</span> }}
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Form.Group</span> <span class="hljs-attr">controlId</span>=<span class="hljs-string">"first_name"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Form.Label</span>&gt;</span>First Name<span class="hljs-tag">&lt;/<span class="hljs-name">Form.Label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"first_name"</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your first name"</span>
          <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"off"</span>
          <span class="hljs-attr">ref</span>=<span class="hljs-string">{register({</span>
            <span class="hljs-attr">required:</span> '<span class="hljs-attr">First</span> <span class="hljs-attr">name</span> <span class="hljs-attr">is</span> <span class="hljs-attr">required.</span>',
            <span class="hljs-attr">pattern:</span> {
              <span class="hljs-attr">value:</span> /^[<span class="hljs-attr">a-zA-Z</span>]+$/,
              <span class="hljs-attr">message:</span> '<span class="hljs-attr">First</span> <span class="hljs-attr">name</span> <span class="hljs-attr">should</span> <span class="hljs-attr">contain</span> <span class="hljs-attr">only</span> <span class="hljs-attr">characters.</span>'
            }
          })}
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">errors.first_name</span> ? '<span class="hljs-attr">input-error</span>' <span class="hljs-attr">:</span> ''}`}
        /&gt;</span>
        {errors.first_name &amp;&amp; (
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorMsg"</span>&gt;</span>{errors.first_name.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        )}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Form.Group</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Form.Group</span> <span class="hljs-attr">controlId</span>=<span class="hljs-string">"last_name"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Form.Label</span>&gt;</span>Last Name<span class="hljs-tag">&lt;/<span class="hljs-name">Form.Label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"last_name"</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your last name"</span>
          <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"off"</span>
          <span class="hljs-attr">ref</span>=<span class="hljs-string">{register({</span>
            <span class="hljs-attr">required:</span> '<span class="hljs-attr">Last</span> <span class="hljs-attr">name</span> <span class="hljs-attr">is</span> <span class="hljs-attr">required.</span>',
            <span class="hljs-attr">pattern:</span> {
              <span class="hljs-attr">value:</span> /^[<span class="hljs-attr">a-zA-Z</span>]+$/,
              <span class="hljs-attr">message:</span> '<span class="hljs-attr">Last</span> <span class="hljs-attr">name</span> <span class="hljs-attr">should</span> <span class="hljs-attr">contain</span> <span class="hljs-attr">only</span> <span class="hljs-attr">characters.</span>'
            }
          })}
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">errors.last_name</span> ? '<span class="hljs-attr">input-error</span>' <span class="hljs-attr">:</span> ''}`}
        /&gt;</span>
        {errors.last_name &amp;&amp; (
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorMsg"</span>&gt;</span>{errors.last_name.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        )}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Form.Group</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"primary"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</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">motion.div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">Form</span>&gt;</span></span>
);
</code></pre>
<p>Now, if you check the application, you will see the sliding animation on page load:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/sliding_animation.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, the form slides in from the left side of the page but it does not yet look very smooth.</p>
<p>To make it a smooth animation, we can provide another <code>transition</code> prop in addition to the <code>initial</code> and <code>animate</code> props.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
  <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6 offset-md-3"</span>
  <span class="hljs-attr">initial</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">x:</span> '<span class="hljs-attr">-100vw</span>' }}
  <span class="hljs-attr">animate</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">x:</span> <span class="hljs-attr">0</span> }}
  <span class="hljs-attr">transition</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">stiffness:</span> <span class="hljs-attr">150</span> }}
&gt;</span>
...
<span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span>
</code></pre>
<p>Here, we've added a <code>transition</code> prop with value of <code>150</code> for <code>stiffness</code>. You can try changing the value from <code>150</code> to something else and check which one looks best to you. I will use <code>150</code> here.</p>
<p>Now, if you check the application, you will see a smooth sliding animation on page load:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/smooth_animation.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Let's make the same animation changes in the <code>SecondStep.js</code> and <code>ThirdStep.js</code> files:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { motion } <span class="hljs-keyword">from</span> <span class="hljs-string">'framer-motion'</span>;
...
&lt;motion.div
  className=<span class="hljs-string">"col-md-6 offset-md-3"</span>
  initial={{ <span class="hljs-attr">x</span>: <span class="hljs-string">'-100vw'</span> }}
  animate={{ <span class="hljs-attr">x</span>: <span class="hljs-number">0</span> }}
  transition={{ <span class="hljs-attr">stiffness</span>: <span class="hljs-number">150</span> }}
&gt;
...
&lt;/motion.div&gt;
</code></pre>
<p>Now if you check the application, you will see a smooth sliding animation on page load for all 3 steps:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/all_steps_animation.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-setup-the-backend-with-nodejs">How to Setup the Backend with Node.js</h2>
<p>We're done with all the basic functionality for the front-end. Now let's setup the backend server code so we can save the data entered in the form to MongoDB.</p>
<p>Create a new folder with the name <code>server</code> outside the <code>src</code> folder. Then create <code>models</code> and <code>routers</code> folders inside the <code>server</code> folder.</p>
<p>Now, execute the following command from the <code>server</code> folder from the terminal:</p>
<pre><code class="lang-javascript">yarn init -y
</code></pre>
<p>This will create a <code>package.json</code> file inside the <code>server</code> folder so we can manage the dependencies.</p>
<p>Now, install the required dependencies by executing the following command from the <code>server</code> folder from terminal:</p>
<pre><code class="lang-javascript">yarn add bcryptjs@<span class="hljs-number">2.4</span><span class="hljs-number">.3</span> cors@<span class="hljs-number">2.8</span><span class="hljs-number">.5</span> express@<span class="hljs-number">4.17</span><span class="hljs-number">.1</span> mongoose@<span class="hljs-number">5.11</span><span class="hljs-number">.18</span> nodemon@<span class="hljs-number">2.0</span><span class="hljs-number">.7</span>
</code></pre>
<p>Next, create a new file with the name <code>.gitignore</code> inside the <code>server</code> folder and add the following line inside it so the <code>node_modules</code> folder will not be pushed to GitHub (if you decide to push your code to GitHub):</p>
<pre><code class="lang-javascript">node_modules
</code></pre>
<p>Create a new file <code>db.js</code> inside the <code>server</code> folder with the following content:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);

mongoose.connect(<span class="hljs-string">'mongodb://127.0.0.1:27017/form-user'</span>, {
  <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">useCreateIndex</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span>
});
</code></pre>
<p>Here, we're using the <code>mongoose</code> library to work with MongoDB. For the <code>mongoose.connect</code> method, we've provided a connection string with the <code>form-user</code> database as the name of the database.</p>
<p>You can give whatever name you want instead of <code>form-user</code>.</p>
<p>Now, create a new file with the name <code>index.js</code> inside the <code>server</code> folder and add the following contents inside it:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-built_in">require</span>(<span class="hljs-string">'./db'</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">3030</span>;

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">'&lt;h2&gt;This is from index.js file&lt;/h2&gt;'</span>);
});

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`server started on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre>
<p>Now, open the <code>server/package.json</code> file and add the <code>scripts</code> section inside it:</p>
<pre><code class="lang-js"><span class="hljs-string">"scripts"</span>: {
  <span class="hljs-string">"start"</span>: <span class="hljs-string">"nodemon index.js"</span>
},
</code></pre>
<p>Here we're using the <code>nodemon</code> npm package that will restart the Express server if we make any changes in <code>index.js</code> or the files included in the <code>index.js</code> file. This way we don't have to manually restart the server on every change.</p>
<p>So your entire <code>package.json</code> file will look like this:</p>
<pre><code class="lang-js">{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"server"</span>,
  <span class="hljs-string">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-string">"main"</span>: <span class="hljs-string">"index.js"</span>,
  <span class="hljs-string">"license"</span>: <span class="hljs-string">"MIT"</span>,
  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"nodemon index.js"</span>
  },
  <span class="hljs-string">"dependencies"</span>: {
    <span class="hljs-string">"bcryptjs"</span>: <span class="hljs-string">"2.4.3"</span>,
    <span class="hljs-string">"cors"</span>: <span class="hljs-string">"2.8.5"</span>,
    <span class="hljs-string">"express"</span>: <span class="hljs-string">"4.17.1"</span>,
    <span class="hljs-string">"mongoose"</span>: <span class="hljs-string">"5.11.18"</span>,
    <span class="hljs-string">"nodemon"</span>: <span class="hljs-string">"2.0.7"</span>
  }
}
</code></pre>
<p>Now, open another terminal and execute the <code>yarn start</code> command from inside the <code>server</code> folder.</p>
<p>If you access <a target="_blank" href="http://localhost:3030/">http://localhost:3030/</a>, you will see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/server_initial_page.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This shows that our Express server is correctly set up. Let's write Rest APIs to store the user registration data.</p>
<p>Create a new file called <code>user.js</code> inside the <code>server/models</code> folder with the following content:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);

<span class="hljs-keyword">const</span> userSchema = mongoose.Schema(
  {
    <span class="hljs-attr">first_name</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>
    },
    <span class="hljs-attr">last_name</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>
    },
    <span class="hljs-attr">user_email</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>,
      validate(value) {
        <span class="hljs-keyword">if</span> (!value.match(<span class="hljs-regexp">/^[^@ ]+@[^@ ]+\.[^@ .]{2,}$/</span>)) {
          <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Email is not valid.'</span>);
        }
      }
    },
    <span class="hljs-attr">user_password</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">minlength</span>: <span class="hljs-number">6</span>
    },
    <span class="hljs-attr">country</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>
    },
    <span class="hljs-attr">state</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>
    },
    <span class="hljs-attr">city</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>
    }
  },
  {
    <span class="hljs-attr">timestamps</span>: <span class="hljs-literal">true</span>
  }
);

<span class="hljs-keyword">const</span> User = mongoose.model(<span class="hljs-string">'User'</span>, userSchema);

<span class="hljs-built_in">module</span>.exports = User;
</code></pre>
<p>Here, we've created a <code>User</code> schema to define the structure of the data stored in the <code>User</code> collection.</p>
<p>If you have never worked with the <code>mongoose</code> library then check out <a target="_blank" href="https://javascript.plainenglish.io/what-is-so-special-about-mongoose-library-when-working-with-mongodb-65096b97f8ae?source=friends_link&amp;sk=5c98c783bd200aa6ce59aa8b16e56f1f">this article</a> for an introduction.</p>
<h2 id="heading-how-to-create-the-rest-apis">How to Create the REST APIs</h2>
<p>Create a new file called <code>user.js</code> inside the <code>routers</code> folder with the following content:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> User = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../models/user'</span>);
<span class="hljs-keyword">const</span> bcrypt = <span class="hljs-built_in">require</span>(<span class="hljs-string">'bcryptjs'</span>);
<span class="hljs-keyword">const</span> router = express.Router();

router.post(<span class="hljs-string">'/register'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
 <span class="hljs-keyword">const</span> { user_email, user_password } = req.body;

 <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'req.body'</span>, req.body);

 <span class="hljs-keyword">let</span> user = <span class="hljs-keyword">await</span> User.findOne({ user_email });
 <span class="hljs-keyword">if</span> (user) {
   <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">'User with the provided email already exist.'</span>);
 }

 <span class="hljs-keyword">try</span> {
   user = <span class="hljs-keyword">new</span> User(req.body);
   user.user_password = <span class="hljs-keyword">await</span> bcrypt.hash(user_password, <span class="hljs-number">8</span>);

   <span class="hljs-keyword">await</span> user.save();
   res.status(<span class="hljs-number">201</span>).send();
 } <span class="hljs-keyword">catch</span> (e) {
   res.status(<span class="hljs-number">500</span>).send(<span class="hljs-string">'Something went wrong. Try again later.'</span>);
 }
});

<span class="hljs-built_in">module</span>.exports = router;
</code></pre>
<p>Here, we've created a post API for the <code>/register</code> route. We will be passing the data to this API in JSON format. The Express server makes it available inside the <code>req.body</code> object so we're destructuring the email and password value from it:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { user_email, user_password } = req.body;
</code></pre>
<p>Then using the <code>findOne</code> method of the <code>User</code> model, we're first checking if there is any user with the provided email address.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> user = <span class="hljs-keyword">await</span> User.findOne({ user_email });
</code></pre>
<p>If such a user exists, then we're returning an error back to the client (which is our React app).</p>
<pre><code class="lang-js"><span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">'User with the provided email already exist.'</span>);
</code></pre>
<p>It's always good to specify the HTTP response code of the error while sending back the response.</p>
<p>You can find all HTTP status codes and their meanings on <a target="_blank" href="https://httpstatuses.com/">this website</a>.</p>
<p>Then we pass all the user data (like <code>first_name</code>, <code>last_name</code>, <code>user_email</code>, <code>users_password</code>, <code>country</code>, <code>state</code> and <code>city</code>) which is present in the <code>req.body</code> to the <code>User</code> constructor .</p>
<p>But we don't want to store the user-entered data into the database as it is. So we'll use the popular <a target="_blank" href="https://www.npmjs.com/package/bcryptjs">bcryptjs</a> npm library to hash the password before saving it to the database.</p>
<pre><code class="lang-js">user.user_password = <span class="hljs-keyword">await</span> bcrypt.hash(user_password, <span class="hljs-number">8</span>);
</code></pre>
<p>Check out <a target="_blank" href="https://javascript.plainenglish.io/how-to-create-a-strong-and-secure-password-in-nodejs-which-cannot-be-decrypted-24d046b24958?source=friends_link&amp;sk=87160d305a0b0cd97ec18d376a5d7765">my article here</a> to learn about <code>bcryptjs</code> in detail.</p>
<p>And once the password is hashed, we call the <code>save</code> method of the <code>User</code> model to save all the details along with hashed password into the MongoDB database.</p>
<pre><code class="lang-js"><span class="hljs-keyword">await</span> user.save();
</code></pre>
<p>Once we're done, we're sending back the response with the status code of <code>201</code> which describes that something has been created.</p>
<pre><code class="lang-js">res.status(<span class="hljs-number">201</span>).send();
</code></pre>
<p>Note that here we're not sending back any data – just a response saying that the request was successful and a new record was created.</p>
<p>Then at the end, we're exporting the express <code>router</code> so we can use it in the <code>index.js</code> file.</p>
<p>Now, open the <code>server/index.js</code> file and import the user router at the top of the file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> userRouter = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./routers/user'</span>);
</code></pre>
<p>As we're sending the data to register from React app to Node.js server in JSON format, we need to add the following code for the middleware:</p>
<pre><code class="lang-js">app.use(express.json());
</code></pre>
<p>Also, after the <code>PORT</code> constant, add the following line of code:</p>
<pre><code class="lang-js">app.use(userRouter);
</code></pre>
<p>So your entire <code>server/index.js</code> file will look like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> userRouter = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./routers/user'</span>);
<span class="hljs-built_in">require</span>(<span class="hljs-string">'./db'</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">3030</span>;

app.use(express.json());
app.use(userRouter);

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">'&lt;h2&gt;This is from index.js file&lt;/h2&gt;'</span>);
});

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`server started on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre>
<p>Here, we've provided <code>userRouter</code> as a middleware for the Express app so that we can make API requests to it.</p>
<p>It's always good to separate out each router in its own file and include it using the <code>app.use</code> method. This avoids making the code larger by writing it in a single file.</p>
<p>Now, start your local MongoDB database server by running <code>./mongod --dbpath=&lt;path_to_mongodb-data_folder&gt;</code> as explained in <a target="_blank" href="https://levelup.gitconnected.com/how-to-install-mongodb-database-on-local-environment-19a8a76f1b92?source=friends_link&amp;sk=416b443bad1f86b292e4b72602cf5c9b">this article</a> and keep it running.</p>
<p>And then restart the Express server by running <code>yarn start</code> from the <code>server</code> folder and keep it running.</p>
<p>Open another terminal and start the react app by running <code>yarn start</code> if you haven't already done it.</p>
<p>So now you will two separate terminals open – one for running the Express server app and another one running the React app as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/vscode_terminals.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here, we're opening terminals inside VSCode. You can open the first terminal by going to the <code>Terminal -&gt; New Terminal</code> menu in VS Code. Then just click the <code>+</code> icon to open additional terminals.</p>
<h2 id="heading-how-to-call-rest-apis-from-a-react-app">How to Call REST APIs from a React App</h2>
<p>Now, let's make the code changes in our React app to make the API call to our <code>/register</code> API.</p>
<p>Open the <code>ThirdStep.js</code> file and replace the <code>handleSubmit</code> method with the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (event) =&gt; {
    event.preventDefault();

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> { user } = props;
      <span class="hljs-keyword">const</span> updatedData = {
        <span class="hljs-attr">country</span>: countries.find(
          <span class="hljs-function">(<span class="hljs-params">country</span>) =&gt;</span> country.isoCode === selectedCountry
        )?.name,
        <span class="hljs-attr">state</span>:
          states.find(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.isoCode === selectedState)?.name || <span class="hljs-string">''</span>,
        <span class="hljs-attr">city</span>: selectedCity
      };

      <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">`<span class="hljs-subst">${BASE_API_URL}</span>/register`</span>, {
        ...user,
        ...updatedData
      });
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-keyword">if</span> (error.response) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'error'</span>, error.response.data);
      }
    }
  };
</code></pre>
<p>Here, once we submit the form in step 2, we call the <code>handleSubmit</code> method where we make an API call to our <code>/register</code> API:</p>
<pre><code class="lang-js"><span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">`<span class="hljs-subst">${BASE_API_URL}</span>/register`</span>, {
  ...user,
  ...updatedData
});
</code></pre>
<p>Here, we're passing the data to the <code>/register</code> API in the JSON format.</p>
<p>We store the country code in <code>selectedCountry</code> and the state code in <code>selectedState</code> state variables. These are denoted by <code>isoCode</code>, and we first use the array <code>find</code> method to find out the actual names related to that country and state code as shown below:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> updatedData = {
  <span class="hljs-attr">country</span>: countries.find(
    <span class="hljs-function">(<span class="hljs-params">country</span>) =&gt;</span> country.isoCode === selectedCountry
  )?.name,
  <span class="hljs-attr">state</span>:
    states.find(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.isoCode === selectedState)?.name || <span class="hljs-string">''</span>,
  <span class="hljs-attr">city</span>: selectedCity
};
</code></pre>
<p>Inside the <code>selectedCity</code> state variable we store the name so we don't need to use the filter method there.</p>
<p>If you want a quick refresher on the most widely used array methods (including array find method) check out my <a target="_blank" href="https://www.freecodecamp.org/news/complete-introduction-to-the-most-useful-javascript-array-methods/">article here</a>.</p>
<p>While using the <code>find</code> method for state, we've added the <code>||</code> condition. This is because if there is no available state for any selected country, then while accessing <code>?.name</code>, it might come as <code>undefined</code>. To avoid storing <code>undefined</code> in the database, we use the <code>||</code> operator to store an empty string <code>''</code> instead or <code>undefined</code>.</p>
<h2 id="heading-how-to-test-rest-apis">How to Test REST APIs</h2>
<p>Now, let's check the application's functionality.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/cors_error.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, when we try to submit the form in the step 3, we're getting a CORS (Cross-Origin Resource Sharing) error in the browser console.</p>
<p>This is because the browser does not allow us to access the data of an application running on another port – because we're running our React application on port 3000 and our Node.js application on port 3030.</p>
<p>This is for security reasons and violates cross-domain policies.</p>
<p>To fix this, we need to install the <a target="_blank" href="https://www.npmjs.com/package/cors">cors</a> npm package and use it in our <code>server/index.js</code> file so that the Node.js server will allow any application to access its APIs.</p>
<p>Don’t worry, we will see how we can use the Node.js APIs without using <code>cors</code> later in this article. We'll also avoid needing to run two separate terminals to start our React and Node.js server.</p>
<p>For now, open the <code>server/index.js</code> file  and add the import for <code>cors</code> as shown below:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">'cors'</span>);
</code></pre>
<p>Note that we've already installed the <code>cors</code> npm package while creating the Express server earlier.</p>
<p>And add it as an Express middleware before the <code>app.use(userRouter)</code> statement like this:</p>
<pre><code class="lang-js">app.use(express.json());
app.use(cors());
app.use(userRouter);
</code></pre>
<p>Now your <code>index.js</code> file will look like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">'cors'</span>);
<span class="hljs-keyword">const</span> userRouter = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./routers/user'</span>);
<span class="hljs-built_in">require</span>(<span class="hljs-string">'./db'</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">3030</span>;

app.use(express.json());
app.use(cors());
app.use(userRouter);

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">'&lt;h2&gt;This is from index.js file&lt;/h2&gt;'</span>);
});

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`server started on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre>
<p>If you submit the form, you will see that the data has been correctly logged into the console:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/save_log-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And the data also gets saved into the database as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/saved_into_db.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>So now, we've successfully connected our front-end React app to the back-end Node.js app and saved the data to the database.</p>
<h2 id="heading-how-to-show-the-registration-feedback-popup">How to Show the Registration Feedback Popup</h2>
<p>You might have noticed that we're not showing any indication that the data has been successfully saved to the database once we register the user. So let's do that now.</p>
<p>To show the success message, we'll use <a target="_blank" href="https://www.npmjs.com/package/sweetalert2">sweetalert2</a> which is a popular and customizable popup modal library.</p>
<p>Import it in the <code>ThirdStep.js</code> file as shown below:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> Swal <span class="hljs-keyword">from</span> <span class="hljs-string">'sweetalert2'</span>;
</code></pre>
<p>Inside the <code>handleSubmit</code> function, after the <code>axios.post</code> call, add the following code in the try block:</p>
<pre><code class="lang-js">Swal.fire(<span class="hljs-string">'Awesome!'</span>, <span class="hljs-string">"You're successfully registered!"</span>, <span class="hljs-string">'success'</span>).then(
<span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (result.isConfirmed || result.isDismissed) {
    props.history.push(<span class="hljs-string">'/'</span>);
  }
}
);
</code></pre>
<p>and in the catch block add the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">if</span> (error.response) {
  Swal.fire({
    <span class="hljs-attr">icon</span>: <span class="hljs-string">'error'</span>,
    <span class="hljs-attr">title</span>: <span class="hljs-string">'Oops...'</span>,
    <span class="hljs-attr">text</span>: error.response.data
  });
}
</code></pre>
<p>So your <code>handleSubmit</code> function will look like this now:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (event) =&gt; {
    event.preventDefault();

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> { user } = props;
      <span class="hljs-keyword">const</span> updatedData = {
        <span class="hljs-attr">country</span>: countries.find(
          <span class="hljs-function">(<span class="hljs-params">country</span>) =&gt;</span> country.isoCode === selectedCountry
        )?.name,
        <span class="hljs-attr">state</span>:
          states.find(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.isoCode === selectedState)?.name || <span class="hljs-string">''</span>, <span class="hljs-comment">// or condition added because selectedState might come as undefined</span>
        <span class="hljs-attr">city</span>: selectedCity
      };

      <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">`<span class="hljs-subst">${BASE_API_URL}</span>/register`</span>, {
        ...user,
        ...updatedData
      });
      Swal.fire(<span class="hljs-string">'Awesome!'</span>, <span class="hljs-string">"You're successfully registered!"</span>, <span class="hljs-string">'success'</span>).then(
        <span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> {
          <span class="hljs-keyword">if</span> (result.isConfirmed || result.isDismissed) {
            props.history.push(<span class="hljs-string">'/'</span>);
          }
        }
      );
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-keyword">if</span> (error.response) {
        Swal.fire({
          <span class="hljs-attr">icon</span>: <span class="hljs-string">'error'</span>,
          <span class="hljs-attr">title</span>: <span class="hljs-string">'Oops...'</span>,
          <span class="hljs-attr">text</span>: error.response.data
        });
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'error'</span>, error.response.data);
      }
    }
  };
</code></pre>
<p>If you check the application, you will see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/email_error.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, if the user with the email address already exists in the database then we show an error message from the catch block.</p>
<p>And if the user email does not exist in the database, then we see the success popup as you can see below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/success_register.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you check the code of the popup for success, it looks like this:</p>
<pre><code class="lang-js">Swal.fire(<span class="hljs-string">'Awesome!'</span>, <span class="hljs-string">"You're successfully registered!"</span>, <span class="hljs-string">'success'</span>).then(
  <span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (result.isConfirmed || result.isDismissed) {
      props.history.push(<span class="hljs-string">'/'</span>);
    }
  }
);
</code></pre>
<p>So if the user clicks on the <code>OK</code>  button or clicks outside the popup modal, we redirect the user to step 1 using <code>props.history.push('/');</code>. But we also should clear the user-entered data from the input fields once the registration is successful. Let's do that now.</p>
<p>If you remember, we added a <code>resetUser</code> function inside the <code>AppRouter</code> component to clear the <code>user</code> state data.</p>
<p>Let's pass this function as a prop to the <code>ThirdStep</code> component. So your <code>ThirdStep</code> route will look like this:</p>
<pre><code class="lang-js">&lt;Route
  render={<span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ThirdStep</span>
      {<span class="hljs-attr">...props</span>}
      <span class="hljs-attr">user</span>=<span class="hljs-string">{user}</span>
      <span class="hljs-attr">updateUser</span>=<span class="hljs-string">{updateUser}</span>
      <span class="hljs-attr">resetUser</span>=<span class="hljs-string">{resetUser}</span>
    /&gt;</span></span>
  )}
  path=<span class="hljs-string">"/third"</span>
/&gt;
</code></pre>
<p>And inside the <code>handleSubmit</code> function of the <code>ThirdStep.js</code> file, before calling <code>props.history.push('/');</code> call the <code>resetUser</code> function like this:</p>
<pre><code class="lang-js">Swal.fire(<span class="hljs-string">'Awesome!'</span>, <span class="hljs-string">"You're successfully registered!"</span>, <span class="hljs-string">'success'</span>).then(
  <span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (result.isConfirmed || result.isDismissed) {
      props.resetUser();
      props.history.push(<span class="hljs-string">'/'</span>);
    }
  }
);
</code></pre>
<p>Now, if you register a new user, you will see that after registration, you will be redirected to step 1 and all the input fields will also be cleared.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/cleared_fields.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-add-login-functionality-to-the-app">How to Add Login Functionality to the App</h2>
<p>We have added the entire registration functionality for the front-end and back-end. Let's add login functionality so we can check if a user with a provided email and password already exists and then retrieve the details of that user.</p>
<p>Open the <code>routers/user.js</code> file and add the following code inside it before the <code>module.exports</code> statement:</p>
<pre><code class="lang-js">router.post(<span class="hljs-string">'/login'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findOne({ <span class="hljs-attr">user_email</span>: req.body.user_email });
    <span class="hljs-keyword">if</span> (!user) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">'User with provided email does not exist.'</span>);
    }

    <span class="hljs-keyword">const</span> isMatch = <span class="hljs-keyword">await</span> bcrypt.compare(
      req.body.user_password,
      user.user_password
    );

    <span class="hljs-keyword">if</span> (!isMatch) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">'Invalid credentials.'</span>);
    }
    <span class="hljs-keyword">const</span> { user_password, ...rest } = user.toObject();

    <span class="hljs-keyword">return</span> res.send(rest);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).send(<span class="hljs-string">'Something went wrong. Try again later.'</span>);
  }
});
</code></pre>
<p>Here, we're first checking to see if the user with the provided email already exists using the <code>findOne</code> method. If no such user exists, then we return an error with a status code of <code>400</code>.</p>
<p>If there is a user with the provided email address then we use the <code>bcrypt.compare</code> method to compare the original non-hashed password with the hashed password. If the hashed password does not match with the password from the <code>user</code> object, then we return an error saying <code>Invalid credentials</code>.</p>
<p>But if the password matches, then we create a new <code>rest</code> object with all the <code>user</code> properties except the hashed password using the ES9 rest operator for objects:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { user_password, ...rest } = user.toObject();
</code></pre>
<p>This is because we don't want to return back the hashed password for security reasons.</p>
<p>Then we will send back the <code>rest</code> object with the password removed back to the client (our React app).</p>
<p>Now that we've created the back-end API, let's integrate the front-end part for our login functionality.</p>
<p>Create a new file called <code>Login.js</code> inside the <code>components</code> folder with the following code:</p>
<pre><code class="lang-jsx"><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> { useForm } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-hook-form'</span>;
<span class="hljs-keyword">import</span> { Form, Button } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-bootstrap'</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> { BASE_API_URL } <span class="hljs-keyword">from</span> <span class="hljs-string">'../utils/constants'</span>;

<span class="hljs-keyword">const</span> Login = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { register, handleSubmit, errors } = useForm();
  <span class="hljs-keyword">const</span> [successMessage, setSuccessMessage] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [errorMessage, setErrorMessage] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [userDetails, setUserDetails] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> onSubmit = <span class="hljs-keyword">async</span> (data) =&gt; {
    <span class="hljs-built_in">console</span>.log(data);

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">`<span class="hljs-subst">${BASE_API_URL}</span>/login`</span>, data);
      setSuccessMessage(<span class="hljs-string">'User with the provided credentials found.'</span>);
      setErrorMessage(<span class="hljs-string">''</span>);
      setUserDetails(response.data);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(error);
      <span class="hljs-keyword">if</span> (error.response) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'error'</span>, error.response.data);
        setErrorMessage(error.response.data);
      }
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"input-form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit(onSubmit)}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6 offset-md-3"</span>&gt;</span>
        {errorMessage ? (
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorMsg login-error"</span>&gt;</span>{errorMessage}<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 class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"successMsg"</span>&gt;</span>{successMessage}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

            {userDetails &amp;&amp; (
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"user-details"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Following are the user details:<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>First name: {userDetails.first_name}<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>Last name: {userDetails.last_name}<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>Email: {userDetails.user_email}<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>Country: {userDetails.country}<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>State: {userDetails.state}<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>City: {userDetails.city}<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 class="hljs-tag">&lt;<span class="hljs-name">Form.Group</span> <span class="hljs-attr">controlId</span>=<span class="hljs-string">"first_name"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Label</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">Form.Label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"user_email"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your email address"</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{register({</span>
              <span class="hljs-attr">required:</span> '<span class="hljs-attr">Email</span> <span class="hljs-attr">is</span> <span class="hljs-attr">required.</span>',
              <span class="hljs-attr">pattern:</span> {
                <span class="hljs-attr">value:</span> /^[^@ ]+@[^@ ]+\<span class="hljs-attr">.</span>[^@ <span class="hljs-attr">.</span>]{<span class="hljs-attr">2</span>,}$/,
                <span class="hljs-attr">message:</span> '<span class="hljs-attr">Email</span> <span class="hljs-attr">is</span> <span class="hljs-attr">not</span> <span class="hljs-attr">valid.</span>'
              }
            })}
            <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">errors.user_email</span> ? '<span class="hljs-attr">input-error</span>' <span class="hljs-attr">:</span> ''}`}
          /&gt;</span>
          {errors.user_email &amp;&amp; (
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorMsg"</span>&gt;</span>{errors.user_email.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          )}
        <span class="hljs-tag">&lt;/<span class="hljs-name">Form.Group</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Form.Group</span> <span class="hljs-attr">controlId</span>=<span class="hljs-string">"password"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Label</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">Form.Label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"user_password"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Choose a password"</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{register({</span>
              <span class="hljs-attr">required:</span> '<span class="hljs-attr">Password</span> <span class="hljs-attr">is</span> <span class="hljs-attr">required.</span>',
              <span class="hljs-attr">minLength:</span> {
                <span class="hljs-attr">value:</span> <span class="hljs-attr">6</span>,
                <span class="hljs-attr">message:</span> '<span class="hljs-attr">Password</span> <span class="hljs-attr">should</span> <span class="hljs-attr">have</span> <span class="hljs-attr">at-least</span> <span class="hljs-attr">6</span> <span class="hljs-attr">characters.</span>'
              }
            })}
            <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">errors.user_password</span> ? '<span class="hljs-attr">input-error</span>' <span class="hljs-attr">:</span> ''}`}
          /&gt;</span>
          {errors.user_password &amp;&amp; (
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorMsg"</span>&gt;</span>{errors.user_password.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          )}
        <span class="hljs-tag">&lt;/<span class="hljs-name">Form.Group</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"primary"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>
          Check Login
        <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>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Form</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Login;
</code></pre>
<p>Now, open the <code>AppRouter.js</code> file and add a route for Login at the end of all routes before the ending <code>Switch</code> tag like this:</p>
<pre><code class="lang-jsx">&lt;BrowserRouter&gt;
     ...
    &lt;Route component={Login} path=<span class="hljs-string">"/login"</span> /&gt;
    &lt;/Switch&gt;
  &lt;/div&gt;
&lt;/BrowserRouter&gt;
</code></pre>
<p>Also, include the <code>Login</code> component at the top:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> Login <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/Login'</span>;
</code></pre>
<p>Now, if you access <a target="_blank" href="http://localhost:3000/login">http://localhost:3000/login</a>, you will see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/login_screen.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here, we actually don't need to show the steps in the header, so let's add a condition to hide them on the login page.</p>
<p>Open the <code>Progress.js</code> file and add another const variable like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> isLoginPage = pathname === <span class="hljs-string">'/login'</span>;
</code></pre>
<p>Then add a ternary operator condition before the start of the div with class <code>steps</code>:</p>
<pre><code class="lang-jsx">&lt;React.Fragment&gt;
  {!isLoginPage ? (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"steps"</span>&gt;</span>
     ...
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></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>
  )}
&lt;/React.Fragment&gt;
</code></pre>
<p>If the page is not a login page, then we'll display the steps – otherwise we will display an empty div.</p>
<p>Note that we need to render an empty div if we don't have anything to render, because React will throw an error if we don't return any JSX from the component.</p>
<p>Your entire <code>Progress.js</code> file will look like this now:</p>
<pre><code class="lang-jsx"><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> { Link, withRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;

<span class="hljs-keyword">const</span> Progress = <span class="hljs-function">(<span class="hljs-params">{ location: { pathname } }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> isFirstStep = pathname === <span class="hljs-string">'/'</span>;
  <span class="hljs-keyword">const</span> isSecondStep = pathname === <span class="hljs-string">'/second'</span>;
  <span class="hljs-keyword">const</span> isThirdStep = pathname === <span class="hljs-string">'/third'</span>;
  <span class="hljs-keyword">const</span> isLoginPage = pathname === <span class="hljs-string">'/login'</span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.Fragment</span>&gt;</span>
      {!isLoginPage ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"steps"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">isFirstStep</span> ? '<span class="hljs-attr">step</span> <span class="hljs-attr">active</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">step</span>'}`}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>1<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>
              {isSecondStep || isThirdStep ? (
                <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>Step 1<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
              ) : (
                'Step 1'
              )}
            <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">{</span>`${<span class="hljs-attr">isSecondStep</span> ? '<span class="hljs-attr">step</span> <span class="hljs-attr">active</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">step</span>'}`}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>2<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>
              {isThirdStep ? <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/second"</span>&gt;</span>Step 2<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span> : 'Step 2'}
            <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">{</span>`${<span class="hljs-attr">pathname</span> === <span class="hljs-string">'/third'</span> ? '<span class="hljs-attr">step</span> <span class="hljs-attr">active</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">step</span>'}`}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>3<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>Step 3<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 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">React.Fragment</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> withRouter(Progress);
</code></pre>
<h2 id="heading-how-to-test-the-login-functionality">How to Test the Login Functionality</h2>
<p>Now, if you check the login page, you will see the page without steps in the header. But the steps are still displayed for the other pages.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/login_without_steps.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And if you enter the correct login credentials then you will get the details related to that user as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/login_success_message.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If the login credentials are invalid, you will see the error message as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/invalid_login.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If the email exists but the password does not match, then you will see the error message as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/invalid_credentials.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, let's understand the code from the <code>Login.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> onSubmit = <span class="hljs-keyword">async</span> (data) =&gt; {
  <span class="hljs-built_in">console</span>.log(data);

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">`<span class="hljs-subst">${BASE_API_URL}</span>/login`</span>, data);
    setSuccessMessage(<span class="hljs-string">'User with the provided credentials found.'</span>);
    setErrorMessage(<span class="hljs-string">''</span>);
    setUserDetails(response.data);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
    <span class="hljs-keyword">if</span> (error.response) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'error'</span>, error.response.data);
      setErrorMessage(error.response.data);
    }
  }
};
</code></pre>
<p>In the <code>onSubmit</code> function, we're making an API call to the <code>/login</code> endpoint by passing the data entered in the login form.</p>
<p>If there is no error in the API response, we will set the <code>successMessage</code> state and set the <code>userDetails</code> state with the response from the API. Otherwise we will set the <code>errorMessage</code> state.</p>
<p>And in the JSX, if the <code>errorMessage</code> state is not empty, we'll display the error message otherwise display <code>successMessage</code> state value with the <code>userDetails</code> data:</p>
<pre><code class="lang-jsx">{errorMessage ? (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorMsg login-error"</span>&gt;</span>{errorMessage}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></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">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"successMsg"</span>&gt;</span>{successMessage}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

    {userDetails &amp;&amp; (
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"user-details"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Following are the user details:<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>First name: {userDetails.first_name}<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>Last name: {userDetails.last_name}<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>Email: {userDetails.user_email}<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>Country: {userDetails.country}<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>State: {userDetails.state}<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>City: {userDetails.city}<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>Note that we have not provided a link for the login page on the screen because the application is meant to display multi-step form functionality. I have included the login page so you can get an idea of how to validate user login.</p>
<p>If you want, you can include the login page link in the header or directly access it using <a target="_blank" href="http://localhost:3000/login">http://localhost:3000/login</a>.</p>
<h2 id="heading-how-to-setup-an-invalid-route-page">How to Setup an Invalid Route Page</h2>
<p>Now, we're done with the entire functionality of the App. Let's add some code so that if we enter any invalid route in the browser URL, the user will be redirected back to the home page.</p>
<p>Currently, if you access any invalid route like <a target="_blank" href="http://localhost:3000/contact">http://localhost:3000/contact</a>, you will see a blank page. But there is also no error in the console because there is no matching route in the list of routes inside the <code>AppRouter.js</code> file.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/blank_page-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Open the <code>AppRouter.js</code> file, and after the login route enter another route as shown below:</p>
<pre><code class="lang-jsx">  ...
  &lt;Route component={Login} path=<span class="hljs-string">"/login"</span> /&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">render</span>=<span class="hljs-string">{()</span> =&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">Redirect</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span> /&gt;</span>} /&gt;</span>
&lt;/Switch&gt;
</code></pre>
<p>Here, we haven't provided any path to the <code>Route</code> component for the last Route. This means that if any of the above routes do not match, this last Route will be executed. This will redirect the user to the <code>/</code> Route which is the <code>FirstPage</code> component route.</p>
<p>Also, import the <code>Redirect</code> component from the <code>react-router-dom</code> at the top of the file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { BrowserRouter, Redirect, Route, Switch } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
</code></pre>
<p>Note that you need to enter it as the last route only. This way if any of the above routes do not match, the last route will be executed and it will redirect to the home page.</p>
<p>Let's verify it now.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/page_not_found.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, for all invalid routes we're redirected to the home page which is the first step page.</p>
<h2 id="heading-how-to-get-rid-of-the-cors-library">How to Get Rid of the CORS Library</h2>
<p>As you know, to run this application, we need to start our React app using the <code>yarn start</code> command in one terminal. We also need to execute the <code>yarn start</code> command from the <code>server</code> folder for the backend server. And finally, we also need to keep our MongoDB server running in the third terminal.</p>
<p>So let's remove the need to run two separate <code>yarn start</code> commands. This will also allow you to deploy your app on a single hosting provider.</p>
<p>If you remember, in the <code>server/index.js</code> file, we added the following code:</p>
<pre><code class="lang-js">app.use(cors());
</code></pre>
<p>Adding this code allows any application to access our APIs – which is fine when working in a local environment. But it's not safe to allow everyone to access our APIs. So let's fix that.</p>
<p>Open the <code>server/index.js</code> file and add the below code just above the <code>app.use(express.json());</code> line:</p>
<pre><code class="lang-js">app.use(express.static(path.join(__dirname, <span class="hljs-string">'..'</span>, <span class="hljs-string">'build'</span>)));
</code></pre>
<p>Here, we're configuring our Express app to use the contents of the <code>build</code> folder as a starting point of our app.</p>
<p>The <code>build</code> folder will be created when we run the <code>yarn build</code> command for our React app.</p>
<p>As the <code>build</code> folder will be created outside the <code>server</code> folder, we're using <code>..</code> to come out of the <code>server</code> folder to access it.</p>
<p>Also, import the <code>path</code> Node package at the top of the file:</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>);
</code></pre>
<p>We don't need to install the <code>path</code> npm package, as it's added by default when we install Node.js on our system.</p>
<p>Now, you can remove the <code>cors</code> import and its use from the <code>server/index.js</code> file.</p>
<p>Your final <code>server/index.js</code> file will 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> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> userRouter = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./routers/user'</span>);
<span class="hljs-built_in">require</span>(<span class="hljs-string">'./db'</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">3030</span>;

app.use(express.static(path.join(__dirname, <span class="hljs-string">'..'</span>, <span class="hljs-string">'build'</span>)));
app.use(express.json());
app.use(userRouter);

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
 res.send(<span class="hljs-string">'&lt;h2&gt;This is from index.js file&lt;/h2&gt;'</span>);
});

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
 <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`server started on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre>
<p>Now stop both the <code>yarn start</code> commands from both the terminals. Then, only in one terminal execute the <code>yarn build</code> command from inside the <code>multi-step-form-using-mern</code> folder which is our project folder.</p>
<p>The <code>yarn build</code> command will take some time to complete as it performs some optimizations. It should only be executed when we're done with all the app functionality and when we're ready to deploy the app to production.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/build_completed.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Once the command completes successfully, you will see a <code>build</code> folder created as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/file_structure.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The <code>build</code> folder contains our entire React app so you can use this <code>build</code> folder to deploy your app to production.</p>
<p>Now, open the <code>src/utils/constants.js</code> file and replace this code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> BASE_API_URL = <span class="hljs-string">'http://localhost:3030'</span>;
</code></pre>
<p>with the below code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> BASE_API_URL = <span class="hljs-string">''</span>;
</code></pre>
<p>Now, as we've created the <code>build</code> folder, navigate to <code>server</code> folder from the terminal and execute the <code>yarn start</code> command:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/server_started.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, the server has started on port <code>3030</code>. </p>
<p>So let's access our application at <a target="_blank" href="http://localhost:3030/">http://localhost:3030/</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/complete_flow.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, we only need to run one <code>yarn start</code> command to start the Node.js Express server. The Node.js server renders our React app on port <code>3030</code> from the <code>build</code> folder. </p>
<p>So all our APIs are available now on <code>http://localhost:3030</code> such as <code>http://localhost:3030/register</code> and <code>http://localhost:3030/login</code>.</p>
<p>Therefore we have changed the <code>BASE_API_URL</code> value to just an empty string:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> BASE_API_URL = <span class="hljs-string">''</span>;
</code></pre>
<p>When we're already on <code>http://localhost:3030</code> we can make all our POST request APIs using just <code>/login</code> and <code>/register</code>.</p>
<p>So we only need one terminal to run the <code>yarn start</code> command and another terminal for starting the MongoDB service. This means that we can deploy our app on single hosting provider like <a target="_blank" href="https://www.heroku.com/">heroku</a> instead of deploying the React app on one hosting provider and the Node.js app on another hosting provider.</p>
<p>Note that if you make any changes to the React app's code, you will need to re-run the <code>yarn build</code> command from the project folder and then <code>yarn start</code> command from the <code>server</code> folder.</p>
<p>But there is one issue with this setup. If you directly go to any route apart from the <code>/</code> route like <code>/first</code>, <code>/second</code>, <code>/login</code> and so on, you will get an error as you'll see below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/error.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This is because we’re starting the server from Express.js so the request will always go to the Express server (our Node server was created using Express) and there is no <code>/second</code> route for handling that on the Node side. So it gives us an error.</p>
<p>To fix this, open the <code>server/index.js</code> file and add the following code before the <code>app.listen</code> statement and after all other routes:</p>
<pre><code class="lang-js">app.use(<span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> {
  res.sendFile(path.join(__dirname, <span class="hljs-string">'..'</span>, <span class="hljs-string">'build'</span>, <span class="hljs-string">'index.html'</span>));
});
</code></pre>
<p>This code will act as a default route. If any of the previous routes do not match, this code will send back the <code>index.html</code> file from the <code>build</code> folder which is our React app.</p>
<p>And because the <code>/second</code> route is present in our React app, you will see the correct step 2 page.</p>
<p>If the entered route is not present on the Node.js app as well as in our React app, then the user will be redirected to the step 1 page (our home page) because of our last route in the <code>AppRouter.js</code> file.</p>
<pre><code class="lang-js">&lt;Route render={<span class="hljs-function">() =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Redirect</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span> /&gt;</span></span>} /&gt;
</code></pre>
<p>At this point, your complete <code>server/index.js</code> file will 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> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> userRouter = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./routers/user'</span>);
<span class="hljs-built_in">require</span>(<span class="hljs-string">'./db'</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">3030</span>;

app.use(express.static(path.join(__dirname, <span class="hljs-string">'..'</span>, <span class="hljs-string">'build'</span>)));
app.use(express.json());
app.use(userRouter);

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">'&lt;h2&gt;This is from index.js file&lt;/h2&gt;'</span>);
});

app.use(<span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> {
  res.sendFile(path.join(__dirname, <span class="hljs-string">'..'</span>, <span class="hljs-string">'build'</span>, <span class="hljs-string">'index.html'</span>));
});

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`server started on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre>
<p>And you will not get an error now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/error_fixed.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you want to learn in-depth about rendering React apps using Node.js, check out <a target="_blank" href="https://levelup.gitconnected.com/how-to-render-react-app-using-express-server-in-node-js-a428ec4dfe2b?source=friends_link&amp;sk=3f152ac7908f540b209f07f683b494cd">this article</a>.</p>
<p>Now we're done with both the front-end and back-end functionality as you can see below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/complete_working_app.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-closing-points"><strong>Closing points</strong></h2>
<p>We're done building out the functionality of the App.</p>
<p><strong>You can find the complete GitHub source code for this application in <a target="_blank" href="https://github.com/myogeshchavan97/multi-step-form-using-mern">this repository</a>.</strong></p>
<p>To take your skills further, you can improve the application by adding an extra validation at step 3 to check if the user has entered all the details in the form. This is important because you can directly visit the second step page of the form by using <a target="_blank" href="http://localhost:3030/second">http://localhost:3030/second</a> and proceed from there.</p>
<h3 id="heading-thanks-for-reading">Thanks for reading!</h3>
<p>Want to learn all ES6+ features in detail including let and const, promises, various promise methods, array and object destructuring, arrow functions, async/await, import and export and a whole lot more from scratch?</p>
<p>Check out my <a target="_blank" href="https://modernjavascript.yogeshchavan.dev/">Mastering Modern JavaScript</a> book. This book covers all the pre-requisites for learning React and helps you to become better at JavaScript and React.</p>
<p>Also, you can check out my free <a target="_blank" href="https://yogeshchavan1.podia.com/react-router-introduction">Introduction to React Router</a> course to learn React Router from scratch.</p>
<p>Want to stay up to date with regular content regarding JavaScript, React, and Node.js? <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/">Follow me on LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Deploy a Front End Application with Netlify ]]>
                </title>
                <description>
                    <![CDATA[ Hi everyone! In this article, I'm going to discuss how to deploy an application you've built. The application deployment process might seem complicated, and this might prevent some developers from deploying their applications after they've developed ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-deploy-your-front-end-app/</link>
                <guid isPermaLink="false">66b905d7472b70138041a587</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Front-end Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Netlify ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Idris Olubisi ]]>
                </dc:creator>
                <pubDate>Sat, 09 Jan 2021 00:23:29 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/01/Turquoise-Confetti-Birthday-Greetings-Facebook-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hi everyone! In this article, I'm going to discuss how to deploy an application you've built.</p>
<p>The application deployment process might seem complicated, and this might prevent some developers from deploying their applications after they've developed them. </p>
<p>So here, I will be taking you through a seamless process to spin up your application which can then be accessed anywhere in the world via a URL.</p>
<h3 id="heading-table-of-contents">Table of contents</h3>
<ul>
<li>Why do you need to deploy your frontend applications?</li>
<li>What is Netlify?</li>
<li>What you can do with Netlify</li>
<li>How to deploy your site</li>
<li>Resources</li>
</ul>
<h2 id="heading-why-do-you-need-to-deploy-your-frontend-applications">Why do you need to deploy your frontend applications?</h2>
<p>There are numerous advantages to deploying your applications. Of course, you don't want your beautiful application to sit on your localhost forever. </p>
<p>Deploying your application makes it easier to share your project, side-gig, or startup with potential investors or future employers. If they can see those projects, it helps them gauge your skills. It also lets you show off your progress to the world.</p>
<p>In this article, we will be using the amazing [Netlify](https://www.netlify.com 'Netlify Homepage') platform to deploy our application.</p>
<p>That name sounds familiar, right? But if you haven't used it to deploy a web application yet, trust me I know how you feel. </p>
<p>I will take you through the steps to get your site deployed to <a target="_blank" href="https://www.netlify.com">Netlify</a> in less than 4 minutes. We'll also see some other functionalities that can be done with Netlify out of the box.</p>
<h2 id="heading-what-is-netlify">What is Netlify?</h2>
<p><a target="_blank" href="https://netlify.com/">Netlify</a> is a platform that lets developers automate modern web projects, and it's a place where you can deploy your application without worrying about frustrating configurations. </p>
<p>You can also integrate cool features and dynamic functionality like serverless functions and form handling on Netlify. Sounds good, right?</p>
<h2 id="heading-netlify-features">Netlify Features</h2>
<h3 id="heading-configure-builds">Configure builds</h3>
<p>Netlify helps you run the build command each time you push an update to your repository. </p>
<p>There are additional settings that you can configure like auto-deploy along with other useful deployment settings.</p>
<h3 id="heading-site-deploys-atomic-deployshttpsdocsnetlifycomsite-deploysoverview">Site deploys <a target="_blank" href="https://docs.netlify.com/site-deploys/overview/">(Atomic deploys)</a></h3>
<p>One of the awesome features Netlify has is site deployment. It ensures that your site is deployed and always consistent. </p>
<p>You can also enable deploy notifications, run a test while Netlify compares the new deploy with the existing one, and then update only the files that have been changed.</p>
<h3 id="heading-monitor-sites-netlify-analyticshttpsdocsnetlifycommonitor-sitesanalytics">Monitor sites <a target="_blank" href="https://docs.netlify.com/monitor-sites/analytics/">(Netlify Analytics)</a></h3>
<p>Monitoring your site might become difficult if you don't have proper infrastructure in place. </p>
<p>You can easily monitor your site'sactivities on this platform where you can track each log on the team's build usage.</p>
<h4 id="heading-domains-amp-https-register-new-domainshttpsdocsnetlifycomdomains-httpsnetlify-dnsdomain-registration">Domains &amp; HTTPS <a target="_blank" href="https://docs.netlify.com/domains-https/netlify-dns/domain-registration">(Register new domains)</a></h4>
<p>In simple terms, a domain is the URL anyone types into the browser to visit your site. You can assign a custom domain if you have already purchased one or secure a domain from Netlify. </p>
<p>Either way, the domain name system management is handled by Netlify. They also provide free automatic HTTPS on all sites. Cool right?</p>
<h4 id="heading-routing-learn-about-routinghttpsdocsnetlifycomroutingredirects">Routing <a target="_blank" href="https://docs.netlify.com/routing/redirects/">(Learn about routing)</a></h4>
<p>Routing, Redirects, proxies, and so on all become much easier when your site is deployed on Netlify.</p>
<h3 id="heading-visitor-access">Visitor access</h3>
<p>Here's another cool feature I enjoy: whenever you need to add someone to the team, you can set up role-based access controls that allow the Admin/Senior developer to take control and give access to individuals on the team to avoid escalations.</p>
<h3 id="heading-forms-netlify-formshttpsdocsnetlifycomformssetup">Forms <a target="_blank" href="https://docs.netlify.com/forms/setup/">(Netlify Forms)</a></h3>
<p>When you need to collect data from users on a site deployed on Netlify, you can do so using Netlify forms. This doesn't add API calls or extra JavaScript on your site, either.</p>
<p>Build bots handle form submission by parsing your HTML files directly at deploy time. You can also configure the receiver, group, and notifications.</p>
<h3 id="heading-functions-deploy-serverless-functionshttpsdocsnetlifycomfunctionsoverview">Functions <a target="_blank" href="https://docs.netlify.com/functions/overview/">(Deploy serverless functions)</a></h3>
<p>Serverless functions can be referred to as single-purpose, programmatic functions that are hosted on managed infrastructure.</p>
<p>Netlify lets you deploy serverless Lambda functions with management handled directly within Netlify, while they are built and deployed with the rest of your sites.</p>
<h3 id="heading-the-netlify-cli-netlify-command-line-interfacehttpsdocsnetlifycomcliget-started">The Netlify CLI <a target="_blank" href="https://docs.netlify.com/cli/get-started">(Netlify command-line interface)</a></h3>
<p>You might be wondering if all activities are carried out on the Netlify UI alone - well, no they're not. </p>
<p>There is another great feature that allows developers to deploy sites or do some configuration right from their terminal. The Netlify CLI can be used to run a local development server that can be shared, including plugins.</p>
<h3 id="heading-the-netlify-api-netlify-apihttpsdocsnetlifycomapiget-startedauthentication">The Netlify API <a target="_blank" href="https://docs.netlify.com/api/get-started/#authentication">(Netlify API)</a></h3>
<p>Netlify's API can be used to handle the deployment of sites, script injections, and more. It uses JSON for serialization, which conforms to the REST standard.</p>
<h3 id="heading-accounts-amp-billing">Accounts &amp; billing</h3>
<p>Learn about <a target="_blank" href="https://docs.netlify.com/accounts-and-billing/team-management/manage-team-members">managing team members</a> and how to transfer sites between teams.</p>
<blockquote>
<p>I hope you can now see how powerful Netlify is. Sut seeing sometimes can be deceiving, so let's try it out on our own.</p>
</blockquote>
<p>As you can tell from the title of this article, I will only be showing you how to deploy your site to netlify.com. But to explore other functionalities <a target="_blank" href="https://docs.netlify.com/">click here to read more</a>, practice, and explore.</p>
<h2 id="heading-how-to-deploy-a-site-to-netlify">How to Deploy a Site to Netlify</h2>
<h3 id="heading-step-one">Step One</h3>
<p>Login or signup on netlify.com if you are a new user. It's free :)</p>
<h3 id="heading-step-two">Step Two</h3>
<p>As shown below, all you need is to select a site from Git by clicking on the button with the name “New site from Git”.</p>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119982/netlify%20deploy%20post/Screenshot.png" alt="Netlify" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-three">Step Three</h3>
<p>You will see the interface below where you can choose the Git provider where your site source code is hosted.</p>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119980/netlify%20deploy%20post/select_git.png" alt="Netlify" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-four">Step Four</h3>
<p>Choose the repository you want to link to your site on Netlify.</p>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119980/netlify%20deploy%20post/select_repo.png" alt="Netlify" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-five">Step Five</h3>
<p>We are almost there :)</p>
<p>This section allows you to get more control over how Netlify builds and deploys your site with the settings option shown below:</p>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119981/netlify%20deploy%20post/select_to_deploy_site.jpg" alt="Netlify" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-six">Step Six</h3>
<p>Wait, Netlify is getting things ready for you. :)</p>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119980/netlify%20deploy%20post/site_deploy_in_pgrogress.png" alt="Netlify" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-seven">Step Seven</h3>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119980/netlify%20deploy%20post/site.png" alt="Netlify" width="600" height="400" loading="lazy"></p>
<p>Congratulation Your site is Live!</p>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119980/netlify%20deploy%20post/Screenshot1.png" alt="Netlify" width="600" height="400" loading="lazy"></p>
<p>Click on the generated URL with the .netlify.com extension below the header that states “Deploys for”.</p>
<p><strong>Lastly: You can also set up a new domain or change the generated one to something nice by clicking on the “…” that embeds “Edit site name” but it will end with .netlify.com. <a target="_blank" href="https://docs.netlify.com/domains-https/custom-domains/">Click here to read more</a></strong></p>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119981/netlify%20deploy%20post/domain_setup.png" alt="Netlify" width="600" height="400" loading="lazy"></p>
<p>I hope you have found this guide useful :)</p>
<p>NOTE: the Netlify URL extension is now netlify.app. All netlify.com URLs will now be redirected to netlify.app.</p>
<p><strong>Please don't forget to check out my other articles, it gives me joy :) and the vibes to write more stuff.</strong></p>
<p>You can also reach out to me on <a target="_blank" href="https://twitter.com/olanetsoft">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Rust Programming Language Tutorial – How to Build a To-Do List App ]]>
                </title>
                <description>
                    <![CDATA[ By Claudio Restifo Since its first open-source release in 2015, the Rust programming language has gained a lot of attention from the community. It's also been voted the most loved programming language on StackOverflow's developer survey each year sin... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-to-do-app-with-rust/</link>
                <guid isPermaLink="false">66d45e00d7a4e35e38434959</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 04 Jan 2021 19:16:44 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/01/rust-mascot.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Claudio Restifo</p>
<p>Since its first open-source release in 2015, the Rust programming language has gained a lot of attention from the community. It's also been voted the most loved programming language on <a target="_blank" href="https://insights.stackoverflow.com/survey/2020#technology-most-loved-dreaded-and-wanted-languages">StackOverflow</a>'s developer survey each year since 2016.</p>
<p>Rust was designed by Mozilla and is considered a system programming language (like C or C++). It has no garbage collector, which makes its performance really good. But its design often makes it look and feel very “high-level”.</p>
<p>The learning curve for Rust is considered to be somewhat steep. I am not a master of the language myself, but with this tutorial I'll try to give you a practical approach to some concepts to help you dig in deeper.</p>
<h2 id="heading-what-we-will-build-in-this-hands-on-tutorial">What we will build in this hands-on tutorial</h2>
<p>I have decided to follow the long tradition of JavaScript apps and make a to-do app as our first project. We will work with the command line so some familiarity with it is necessary. You'll also need some knowledge of general programming concepts.</p>
<p>This app will run in the terminal. We will store values as a collection of items and a boolean value representing its active state.</p>
<h2 id="heading-what-we-will-cover-here">What we will cover here</h2>
<ul>
<li>Error handling in Rust.</li>
<li>Options and Null types.</li>
<li>Structs and impl.</li>
<li>Terminal I/O.</li>
<li>File system handling.</li>
<li>Ownership and borrow in Rust.</li>
<li>Match patters.</li>
<li>Iterators and closures.</li>
<li>Using external crates.</li>
</ul>
<h2 id="heading-before-we-begin">Before we begin</h2>
<p>Some advice before we get started, from someone coming from a JavaScript background:</p>
<ul>
<li>Rust is a strongly typed language. This means that we will have to take care of variable types when the compiler isn't able to infer types for us.</li>
<li>Also as opposed to JavaScript, there's no <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Automatic_semicolon_insertion">AFI</a>. This means that we have to type semicolons (";") ourselves unless it is the last statement of a function. In that case you can omit <code>;</code> to have it as a return.</li>
</ul>
<p>Without farther ado, let's get started.</p>
<h2 id="heading-how-to-get-started-with-rust">How to Get Started with Rust</h2>
<p>To get started, download Rust onto your computer. To do so please follow the instructions you find on the <a target="_blank" href="https://www.rust-lang.org/learn/get-started">getting started</a> page of the official Rust website.</p>
<p>There, you will also find instructions to integrate the language with your favorite editor for a better experience.</p>
<p>Along with the Rust compiler itself, Rust comes with a tool called <a target="_blank" href="https://doc.rust-lang.org/cargo/index.html">Cargo</a>. Cargo is the Rust package manager, and to JavaScript developers it'll feel like npm or yarn.</p>
<p>To start a new project, navigate to where you want your project to be created then simply run <code>cargo new &lt;project-name&gt;</code>. In my case I have decided to name my project "todo-cli" so I can run:</p>
<pre><code class="lang-console">$ cargo new todo-cli
</code></pre>
<p>Now navigate to the newly created directory and list its content. You should see two files in there:</p>
<pre><code class="lang-console">$ tree .
.
├── Cargo.toml
└── src
 └── main.rs
</code></pre>
<p>We will work on the <code>src/main.rs</code> file for the rest of this tutorial, so go ahead and open it.</p>
<p>Like many other languages, Rust has a main function that will be run first. <code>fn</code> is how to declare functions while the <code>!</code> in <code>println!</code> is a <a target="_blank" href="https://doc.rust-lang.org/book/ch19-06-macros.html">macro</a>. As you may guess, this program is the Rust version of "<em>hello world!</em>".</p>
<p>To build and run it, simply execute <code>cargo run</code>.</p>
<pre><code class="lang-console">$ cargo run
Hello world!
</code></pre>
<h2 id="heading-how-to-read-the-arguments">How to Read the Arguments</h2>
<p>Our goal is to have our CLI accept two arguments: the first one which will be the action, and the second one which will be the item.</p>
<p>We will start by reading the arguments the user inputs and printing them out.</p>
<p><strong>Replace</strong> the content of main with the following:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> action = std::env::args().nth(<span class="hljs-number">1</span>).expect(<span class="hljs-string">"Please specify an action"</span>);
<span class="hljs-keyword">let</span> item = std::env::args().nth(<span class="hljs-number">2</span>).expect(<span class="hljs-string">"Please specify an item"</span>);

<span class="hljs-built_in">println!</span>(<span class="hljs-string">"{:?}, {:?}"</span>, action, item);
</code></pre>
<p>Let’s start by digesting all this information.</p>
<ul>
<li><code>let</code> <a target="_blank" href="https://doc.rust-lang.org/std/keyword.let.html">[doc]</a> binds a value to a variable.</li>
<li><code>std::env::args()</code> <a target="_blank" href="https://doc.rust-lang.org/std/env/fn.args.html">[doc]</a> is a function brought in from the <em>env</em> module of the standard libray that returns the arguments that the program was started with. Since it's an iterator we can access the value stored at each position with the <code>nth()</code> function. The Argument at position 0 is the program itself, which is why we start reading from the 1st element.</li>
<li><code>expect()</code> <a target="_blank" href="https://doc.rust-lang.org/std/option/enum.Option.html#method.expect">[doc]</a> is a method defined for the <code>Option</code> enum that will either return the value, or if not present will terminate the program immediatly (Panic in Rust terms), returning the provided message.</li>
</ul>
<p>Because the program can be run without arguments, Rust requires us to check whether a value is actually provided by giving us an Option type: either the value is there, or not.</p>
<p>As the programmer we have the responsibility of ensuring that we take the appropriate action in each case.</p>
<p>For the time being, if the argument is not provided we will exit the program immediately.</p>
<p>Let's run the program and pass two arguments. To do so, append them after <code>--</code>. For example:</p>
<pre><code class="lang-console">$ cargo run -- hello world!
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/todo_cli hello 'world'\!''`
"hello", "world!"
</code></pre>
<h2 id="heading-how-to-insert-and-save-data-with-a-custom-type">How to Insert and Save Data with a Custom Type</h2>
<p>Let's think for a moment about our goal for the program. We want to read the argument given by the user, update our todo list, and store it somehwere for usage.</p>
<p>To do so, we will implement our own type where we can define our methods to meets the business needs.</p>
<p>We will use Rust's <a target="_blank" href="https://doc.rust-lang.org/std/keyword.struct.html">struct</a>, which let us do both in a clean way. It avoids having to write all the code inside the main function.</p>
<h3 id="heading-how-to-define-our-struct">How to define our struct</h3>
<p>Since we will type HashMap a lot in the following steps, we can bring it into scope and save ourselves some typing.</p>
<p>At the top of our file add this line:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::collections::HashMap
</code></pre>
<p>This will let us use <code>HashMap</code> directly without the need to type the full path each time.</p>
<p>Below the main function, let's add the following code:</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Todo</span></span> {
    <span class="hljs-comment">// use rust built in HashMap to store key - val pairs</span>
    map: HashMap&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">bool</span>&gt;,
}
</code></pre>
<p>This will define our custom Todo type: a struct with a single field called "map".</p>
<p>This field is a <a target="_blank" href="https://doc.rust-lang.org/std/collections/struct.HashMap.html">HashMap</a>. You can think of it as a <em>kind</em> of JavaScript object, where Rust requires us to declare the types of the key and value.</p>
<ul>
<li><code>HashMap&lt;String, bool&gt;</code> means we have keys composed by Strings, and a boolean value: the active state.</li>
</ul>
<h3 id="heading-how-to-add-methods-to-our-struct">How to add methods to our struct</h3>
<p>Methods are like regular functions – they are delcared with the <code>fn</code> keyword, they accept parameters, and they have a return value. </p>
<p>However they differ from regular function in that are defined within the context of a struct and their first parameters is <em>always</em> <code>self</code>.</p>
<p>We are gonna define an <em>impl</em> (implementation) block below the newly added struct.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Todo {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">insert</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, key: <span class="hljs-built_in">String</span>) {
        <span class="hljs-comment">// insert a new item into our map.</span>
        <span class="hljs-comment">// we pass true as value</span>
        <span class="hljs-keyword">self</span>.map.insert(key, <span class="hljs-literal">true</span>);
    }
}
</code></pre>
<p>This function is pretty straightforward: it's simply taking a <em>reference</em> to the struct and a key, and insterting it into our map using HashMap's built in <a target="_blank" href="https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.insert">insert</a> method.</p>
<p>Two very important piece of information:</p>
<ul>
<li><p><strong>mut</strong> <a target="_blank" href="https://doc.rust-lang.org/std/keyword.mut.html">[doc]</a> makes a variable mutable.
In Rust every variable is <em>immutable</em> by default. If you want to update a value, you need to opt-in mutability using the <code>mut</code> keyword. Since with our function we are effectively changing our map by adding a new value, we need it to be declared as mutable.</p>
</li>
<li><p><strong>&amp;</strong> <a target="_blank" href="https://doc.rust-lang.org/std/primitive.reference.html">[doc]</a> indicates a <em>reference</em>.
You can imagine the varaible as a pointer to the memory location where the value is stored, rather the being the "value" itself.<br>
In Rust terms this is referred to as a <strong>borrow</strong>, meaning that the function doesn't actually own this value, but it's merely pointing to the location where it's stored.</p>
</li>
</ul>
<h2 id="heading-a-brief-overview-of-rusts-ownership-system">A Brief Overview of Rust's Ownership System</h2>
<p>With the previous hint about borrow and reference, it's now a good time to briefly talk about ownership.</p>
<p>Ownership is Rust's most unique feature. It enables Rust programmers to write programs without needing to manually allocate memory (like in C/C++) while still being able to run without a Garbage Collector (like in JavaScript or Python) that constantly looks at the program's memory to free resources not in use.</p>
<p>The ownership system has three rules:</p>
<ul>
<li>Each value in Rust has a variable: its owner.</li>
<li>There can only be one owner at a time for each value.</li>
<li>When the owner goes out of scope, the value will be dropped.</li>
</ul>
<p>Rust checks this rules at compile time, which means that you have to be explicit if and when you want a value to be freed in memory.
Think of this example:</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
 <span class="hljs-comment">// the owner of the String is x</span>
 <span class="hljs-keyword">let</span> x = <span class="hljs-built_in">String</span>::from(<span class="hljs-string">"Hello"</span>);

 <span class="hljs-comment">// we move the value inside this function.</span>
 <span class="hljs-comment">// now doSomething is the owner of x.</span>
 <span class="hljs-comment">// Rust will free the memory associated with x </span>
 <span class="hljs-comment">// as soon as it goes out of "doSomething" scope.</span>
 doSomething(x);

 <span class="hljs-comment">// The compiler will throw an error since we tried to use the value x</span>
 <span class="hljs-comment">// but since we moved it inside "doSomething"</span>
 <span class="hljs-comment">// we cannot use it as we don't have ownership</span>
 <span class="hljs-comment">// and the value may have been dropped.</span>
 <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}"</span>, x);
}
</code></pre>
<p>This concept is widely regarded as the hardest to grasp when learning Rust, as it's a concept that may be new to many programmers. </p>
<p>You can read a more in-depth explanation about <a target="_blank" href="https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html">Ownership</a> from Rust's official docs.</p>
<p>We will not dig too deep into the ins and outs of the ownership system. For now just keep in mind the rules I mentioned above. Try to think, in each step, if we need to "own" the values and then drop them, or if we need a reference of it so it can be kept.</p>
<p>For example in the above insert method, we don't want to own <code>map</code>, as we still need it to store its data somewhere. Only then we can finally free the allocated memory.</p>
<h3 id="heading-how-to-save-the-map-to-disk">How to save the map to disk</h3>
<p>Since this is a demo app, we will adopt the simplest possible solution for long term storage: writing the map into a file to disk.</p>
<p>Let's create a new method in our <code>impl</code> block.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Todo {
    <span class="hljs-comment">// [rest of the code]</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">save</span></span>(<span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;(), std::io::Error&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> content = <span class="hljs-built_in">String</span>::new();
        <span class="hljs-keyword">for</span> (k, v) <span class="hljs-keyword">in</span> <span class="hljs-keyword">self</span>.map {
            <span class="hljs-keyword">let</span> record = <span class="hljs-built_in">format!</span>(<span class="hljs-string">"{}\t{}\n"</span>, k, v);
            content.push_str(&amp;record)
        }
        std::fs::write(<span class="hljs-string">"db.txt"</span>, content)
    }
}
</code></pre>
<ul>
<li><code>-&gt;</code> annotates the returned type from the function. We are returning a <code>Result</code>.</li>
<li>We iterate over the map, and format each string, separating key and value with a tab character and each line with a new line.</li>
<li>We push the formatted string into a content variable.</li>
<li>We write <code>content</code> inside a file called <code>db.txt</code>.</li>
</ul>
<p>It's important to notice that <code>save</code> <em>take ownership</em> of self.
This is an arbitrary decision so that the compiler would stop us if we were to accidentally try to update the map after we called save (as the memory of self would be freed).</p>
<p>This is a personal decision to "enforce" save as the last method to be used. And it's a perfect example to show how you can use Rust's memory management to create stricter code that won't compile (which helps prevent human error during development).</p>
<h3 id="heading-how-to-use-struct-in-main">How to use struct in main</h3>
<p>Now that we have these two methods, we can put them to use. We left off main from the point where we read the arguments supplied. Now if the action supplied is "add" we will insert that item into the file and store it for later use.</p>
<p>Add these lines below the two argument bindings:</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">// ...[arguments bindig code]</span>

    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> todo = Todo {
        map: HashMap::new(),
    };
    <span class="hljs-keyword">if</span> action == <span class="hljs-string">"add"</span> {
        todo.insert(item);
        <span class="hljs-keyword">match</span> todo.save() {
            <span class="hljs-literal">Ok</span>(_) =&gt; <span class="hljs-built_in">println!</span>(<span class="hljs-string">"todo saved"</span>),
            <span class="hljs-literal">Err</span>(why) =&gt; <span class="hljs-built_in">println!</span>(<span class="hljs-string">"An error occurred: {}"</span>, why),
        }
    } 
}
</code></pre>
<p>Let's see what we are doing here:</p>
<ul>
<li><code>let mut todo = Todo</code> let us instantiate a struct, binding it as mutable.</li>
<li>we call the <code>TODO insert</code> method using the <code>.</code> notation.</li>
<li>we <a target="_blank" href="https://doc.rust-lang.org/std/keyword.match.html">match</a> the Result returned from the save function and print a message on screen for both cases.</li>
</ul>
<p>Let's test it. Navigate to your terminal and type:</p>
<pre><code class="lang-console">$ cargo run -- add "code rust"
todo saved
</code></pre>
<p>Let's inspect the saved item:</p>
<pre><code class="lang-console">$ cat db.txt
code rust true
</code></pre>
<p>You can find a full snippet of the code so far in this <a target="_blank" href="https://gist.github.com/Marmiz/b67e98c2fc7be3561d124294cf3cb6ac">gist</a>.</p>
<h2 id="heading-how-to-read-from-file">How to Read From File</h2>
<p>Right now our program has a fundamental flaw: each time we "add" we are overwriting the map instead of updating it. This is because we create a new empty map every time we run the program. Let's fix that.</p>
<h3 id="heading-add-a-new-function-in-todo">Add a new function in TODO</h3>
<p>We are gonna implement a new function for our Todo struct. Once called, it will read the content of our file and give us back our Todo populated with the value previously stored. Note that this is not a method as it's not taking <code>self</code> as the first argument.</p>
<p>We will call it <code>new</code>, which is just a Rust convention (see HashMap::new() as used before).</p>
<p>Let's add the following code inside our impl block:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Todo {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>() -&gt; <span class="hljs-built_in">Result</span>&lt;Todo, std::io::Error&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> f = std::fs::OpenOptions::new()
            .write(<span class="hljs-literal">true</span>)
            .create(<span class="hljs-literal">true</span>)
            .read(<span class="hljs-literal">true</span>)
            .open(<span class="hljs-string">"db.txt"</span>)?;
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> content = <span class="hljs-built_in">String</span>::new();
        f.read_to_string(&amp;<span class="hljs-keyword">mut</span> content)?;
        <span class="hljs-keyword">let</span> map: HashMap&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">bool</span>&gt; = content
            .lines()
            .map(|line| line.splitn(<span class="hljs-number">2</span>, <span class="hljs-string">'\t'</span>).collect::&lt;<span class="hljs-built_in">Vec</span>&lt;&amp;<span class="hljs-built_in">str</span>&gt;&gt;())
            .map(|v| (v[<span class="hljs-number">0</span>], v[<span class="hljs-number">1</span>]))
            .map(|(k, v)| (<span class="hljs-built_in">String</span>::from(k), <span class="hljs-built_in">bool</span>::from_str(v).unwrap()))
            .collect();
        <span class="hljs-literal">Ok</span>(Todo { map })
    }

<span class="hljs-comment">// ...rest of the methods</span>
}
</code></pre>
<p>No worries if this feels a bit overwhelming. We're using a more functional programming style for this one, mainly to showcase and introduce the fact that Rust supports many paradigms found in other languages such as iterators, closure, and lambda functions.</p>
<p>Let's see what is happening here:</p>
<ul>
<li>We are defining a <code>new</code> function that will return a Result that is either a <code>Todo</code> struct or an <code>io:Error</code>.</li>
<li>We configure how to open the "db.txt" file by defining various <a target="_blank" href="https://doc.rust-lang.org/std/fs/struct.OpenOptions.html">OpenOptions</a>. Most notably is the <code>create(true)</code> flag that will create the file if it's not already present.</li>
<li><code>f.read_to_string(&amp;mut content)?</code> reads all the bytes in the file and appends them into the <code>content</code> String.
<em>note:</em> remember to add <code>use std::io::Read;</code> at the top of the file along with the other use statements in order to use the <code>read_to_string</code> method.</li>
<li>We need to convert from the String type of the file to a HashMap. We do so by binding a map variable with this line: <code>let map: HashMap&lt;String, bool&gt;</code>.
This is one of the occasions where the compiler has trouble infering the type for us, so we declare it ourself.</li>
<li>lines <a target="_blank" href="https://doc.rust-lang.org/std/primitive.str.html#method.lines">[doc]</a> creates an Iterator over each line of a string, meaning that now we will iterate on each entry of our file, since we formatted it with a <code>/n</code> at the end of each entry.</li>
<li>map <a target="_blank" href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map">[doc]</a> takes a closure and calls it on each element of the iterator.</li>
<li><code>line.splitn(2, '\t')</code> <a target="_blank" href="https://doc.rust-lang.org/std/primitive.str.html#method.splitn">[doc]</a> will split our lines on the tab character.</li>
<li><code>collect::&lt;Vec&lt;&amp;str&gt;&gt;()</code><a target="_blank" href="https://doc.rust-lang.org/core/iter/trait.Iterator.html#method.collect">[doc]</a> as described in the documentation is one of the most powerful methods in the standard library: it transforms an iterator into a relevant collection.
Here we are telling the map function to transform our Split string into a Vector of borrowed string slices by appending <code>::Vec&lt;&amp;str&gt;</code> to the method. This tells the compiler which collection we want at the end of the operation.</li>
<li>Then we transform it into a tuple for convenience using <code>.map(|v| (v[0], v[1]))</code>.</li>
<li>Then we convert the two elements of the tuple into a String and a boolean using <code>.map(|(k, v)| (String::from(k), bool::from_str(v).unwrap()))</code>.
<em>note:</em> remember to add <code>use std::str::FromStr;</code> at the top of the file along with the other use statement in order to be able to use the <code>from_str</code> method.</li>
<li>We finally collect them into our HashMap. This time we don't need to declare the type as Rust infers it from the binding declaration.</li>
<li>Lastly if we never encountered any errors we return our struct to the caller with <code>Ok(Todo { map })</code>. 
Note here that, much like in JavaScript, we can use a shorter notation if the key and the variable have the same name inside a struct.</li>
</ul>
<p><em>phew!</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/dancing-ferris.gif" alt="dancing ferris." width="600" height="400" loading="lazy">
<em>You are doing great! Image credits: https://rustacean.net/</em></p>
<h3 id="heading-an-alternative-approach">An alternative approach</h3>
<p>Although map is generally considered more idiomatic, the above could have also been implemented with a <code>for</code> loop instead. Feel free to use the one you like the most.</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>() -&gt; <span class="hljs-built_in">Result</span>&lt;Todo, std::io::Error&gt; {
    <span class="hljs-comment">// open the db file</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> f = std::fs::OpenOptions::new()
        .write(<span class="hljs-literal">true</span>)
        .create(<span class="hljs-literal">true</span>)
        .read(<span class="hljs-literal">true</span>)
        .open(<span class="hljs-string">"db.txt"</span>)?;
    <span class="hljs-comment">// read its content into a new string   </span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> content = <span class="hljs-built_in">String</span>::new();
    f.read_to_string(&amp;<span class="hljs-keyword">mut</span> content)?;

    <span class="hljs-comment">// allocate an empty HashMap</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> map = HashMap::new();

    <span class="hljs-comment">// loop over each lines of the file</span>
    <span class="hljs-keyword">for</span> entries <span class="hljs-keyword">in</span> content.lines() {
        <span class="hljs-comment">// split and bind values</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> values = entries.split(<span class="hljs-string">'\t'</span>);
        <span class="hljs-keyword">let</span> key = values.next().expect(<span class="hljs-string">"No Key"</span>);
        <span class="hljs-keyword">let</span> val = values.next().expect(<span class="hljs-string">"No Value"</span>);
        <span class="hljs-comment">// insert them into HashMap</span>
        map.insert(<span class="hljs-built_in">String</span>::from(key), <span class="hljs-built_in">bool</span>::from_str(val).unwrap());
    }
    <span class="hljs-comment">// Return Ok</span>
    <span class="hljs-literal">Ok</span>(Todo { map })
}
</code></pre>
<p>The code above is functionally equivalent to the more "functional" approach used before.</p>
<h3 id="heading-how-to-use-the-new-function">How to use the new function</h3>
<p>Inside main, simply update the binging to our todo variable with:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> todo = Todo::new().expect(<span class="hljs-string">"Initialisation of db failed"</span>);
</code></pre>
<p>Now if we go back to the terminal and run a bunch of "add" commands we should see our database correctly updating:</p>
<pre><code class="lang-console">$ cargo run -- add "make coffee"
todo saved
$ cargo run -- add "make pancakes"
todo saved
$ cat db.txt
make coffee     true
make pancakes   true
</code></pre>
<p>You can find the full code written so far here in this <a target="_blank" href="https://gist.github.com/Marmiz/b659c7835054d25513106e3804c4539f">gist</a>.</p>
<h2 id="heading-how-to-update-a-value-in-the-collection">How to Update a Value in the Collection</h2>
<p>As in all TODO apps out there, we want to be able to not only add items, but to toggle them as well and mark them as completed.</p>
<h3 id="heading-how-to-add-the-complete-method">How to add the complete method</h3>
<p>To do so let's add a new method to our struct called "complete". In it, we take a reference to a key, and update the value, or return <code>None</code> if the key is not present.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Todo {
<span class="hljs-comment">// [Rest of the TODO methods]</span>

  <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">complete</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, key: &amp;<span class="hljs-built_in">String</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;()&gt; {
      <span class="hljs-keyword">match</span> <span class="hljs-keyword">self</span>.map.get_mut(key) {
          <span class="hljs-literal">Some</span>(v) =&gt; <span class="hljs-literal">Some</span>(*v = <span class="hljs-literal">false</span>),
          <span class="hljs-literal">None</span> =&gt; <span class="hljs-literal">None</span>,
      }
  }
}
</code></pre>
<p>Let's see what is happening here:</p>
<ul>
<li>We are declaring our function return type: an empty <code>Option</code>.</li>
<li>The whole method returns the result of the Match expression which will be either an empty <code>Some()</code> or <code>None</code>.</li>
<li><code>self.map.get_mut</code> <a target="_blank" href="https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.get_mut">[doc]</a> will give us a mutable reference to the value of key, or <code>None</code> if the value is not present in the collection.</li>
<li>We are using the <code>*</code> <a target="_blank" href="https://doc.rust-lang.org/book/appendix-02-operators.html">[doc]</a> operator to de-reference the value and set it to false.</li>
</ul>
<h3 id="heading-how-to-use-the-complete-method">How to use the complete method</h3>
<p>We can use the "complete" method in a similar fashion as we used insert before.</p>
<p>In <code>main</code> let's check that the action passed as an argument is "complete" by using an <code>else if</code> statement:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// in the main function</span>

<span class="hljs-keyword">if</span> action == <span class="hljs-string">"add"</span> {
    <span class="hljs-comment">// add action snippet</span>
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> action == <span class="hljs-string">"complete"</span> {
    <span class="hljs-keyword">match</span> todo.complete(&amp;item) {
        <span class="hljs-literal">None</span> =&gt; <span class="hljs-built_in">println!</span>(<span class="hljs-string">"'{}' is not present in the list"</span>, item),
        <span class="hljs-literal">Some</span>(_) =&gt; <span class="hljs-keyword">match</span> todo.save() {
            <span class="hljs-literal">Ok</span>(_) =&gt; <span class="hljs-built_in">println!</span>(<span class="hljs-string">"todo saved"</span>),
            <span class="hljs-literal">Err</span>(why) =&gt; <span class="hljs-built_in">println!</span>(<span class="hljs-string">"An error occurred: {}"</span>, why),
        },
    }
}
</code></pre>
<p>Time to analyze what we are doing here:</p>
<ul>
<li>We match the Option returned by the <code>todo.complete(&amp;item)</code> method.</li>
<li>If the case is <code>None</code> we print a warning to the user for a better experience.
We passed item as a reference with <code>&amp;item</code> to the "todo.complete" method so that the value is still owned by this function. This means we can use it for our <code>println!</code> macro in the following line.
If we were not to do that, the value would have been owned by "complete" and dropped there.</li>
<li>If we detect that <code>Some</code> value has returned, we call <code>todo.save</code> to store the change permanently into our file.</li>
</ul>
<p>As before, you can find a snapshot of the code written so far in this <a target="_blank" href="https://gist.github.com/Marmiz/1480b31e8e0890e8745e7b6b44a803b8">gist</a>.</p>
<h2 id="heading-try-running-the-program">Try Running the Program</h2>
<p>It's time to try out the app we've developed locally in our terminal. Let's start by removing our db file to start fresh.</p>
<pre><code class="lang-console">$ rm db.txt
</code></pre>
<p>Then add and modify some of the todos:</p>
<pre><code class="lang-console">$ cargo run -- add "make coffee"
$ cargo run -- add "code rust"
$ cargo run -- complete "make coffee"
$ cat db.txt
make coffee     false
code rust       true
</code></pre>
<p>Meaning that at the end of these commands we have one completed action ("make coffee") and a pending one: "code rust".</p>
<p>Let's say we want to make coffee again:</p>
<pre><code class="lang-console">$ cargo run -- add "make coffee
$ cat db.txt
make coffee     true
code rust       true
</code></pre>
<h2 id="heading-bonus-how-to-store-it-as-json-with-serde">Bonus: How to Store it as JSON with Serde</h2>
<p>The program, even if minimal, is running. But let's give it a bit of a twist. Coming from the JavaScript world I have decided that instead of a plain text file, I want to store my values as a JSON file.</p>
<p>We are gonna take this opportunity to see how to install and use a package from the Rust open source community called <a target="_blank" href="https://crates.io/">crates.io</a>.</p>
<h3 id="heading-how-to-install-serde">How to install serde</h3>
<p>To install a new package into our project, open the <code>cargo.toml</code> file. At the bottom you should see a <code>[dependencies]</code> field: simply add the following to the file:</p>
<pre><code class="lang-toml"><span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">serde_json</span> = <span class="hljs-string">"1.0.60"</span>
</code></pre>
<p>And that's it. The next time, cargo will compile our program and will also download and include the new package along with our code.</p>
<h3 id="heading-how-to-update-todonew">How to update Todo::New</h3>
<p>The first place where we want to use Serde is when we read the db file. Now instead of reading a ".txt", we want to read a JSON file.</p>
<p>Inside the <code>impl</code> block let's update the <code>new</code> function:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// inside Todo impl block</span>

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>() -&gt; <span class="hljs-built_in">Result</span>&lt;Todo, std::io::Error&gt; {
    <span class="hljs-comment">// open db.json</span>
    <span class="hljs-keyword">let</span> f = std::fs::OpenOptions::new()
        .write(<span class="hljs-literal">true</span>)
        .create(<span class="hljs-literal">true</span>)
        .read(<span class="hljs-literal">true</span>)
        .open(<span class="hljs-string">"db.json"</span>)?;
    <span class="hljs-comment">// serialize json as HashMap</span>
    <span class="hljs-keyword">match</span> serde_json::from_reader(f) {
        <span class="hljs-literal">Ok</span>(map) =&gt; <span class="hljs-literal">Ok</span>(Todo { map }),
        <span class="hljs-literal">Err</span>(e) <span class="hljs-keyword">if</span> e.is_eof() =&gt; <span class="hljs-literal">Ok</span>(Todo {
            map: HashMap::new(),
        }),
        <span class="hljs-literal">Err</span>(e) =&gt; <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"An error occurred: {}"</span>, e),
    }
}
</code></pre>
<p>The notable changes are:</p>
<ul>
<li>No more <code>mut f</code> binding for the file option, as we don't need to manually allocate the content into a String as before. Serde will take care of it for us.</li>
<li>We updated our file extension as <code>db.json</code>.</li>
<li><code>serde_json::from_reader</code> <a target="_blank" href="https://docs.serde.rs/serde_json/fn.from_reader.html">[doc]</a> will deserialize the file for us. It interferes with the return type of map and will attempt to convert our JSON into a compatible HashMap. If all goes well we return our <code>Todo</code> struct as before.</li>
<li><code>Err(e) if e.is_eof()</code> is a <a target="_blank" href="https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards">Match guard</a> that lets us refine the behavior of the Match statement.
If Serde returns as an error a premature EOF (end of file), this means that the file is totally empty (for example on the very first run, or if we deleted the file). In that case we recover from the error and return an empty HashMap.</li>
<li>For all the other errors, exit the program immediately.</li>
</ul>
<h3 id="heading-how-to-update-todosave">How to update Todo.save</h3>
<p>The other place where we want to use Serde is when we save our map as JSON. To do so, update the <code>save</code> method in the impl block to be:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// inside Todo impl block</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">save</span></span>(<span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;(), <span class="hljs-built_in">Box</span>&lt;<span class="hljs-keyword">dyn</span> std::error::Error&gt;&gt; {
    <span class="hljs-comment">// open db.json</span>
    <span class="hljs-keyword">let</span> f = std::fs::OpenOptions::new()
        .write(<span class="hljs-literal">true</span>)
        .create(<span class="hljs-literal">true</span>)
        .open(<span class="hljs-string">"db.json"</span>)?;
    <span class="hljs-comment">// write to file with serde</span>
    serde_json::to_writer_pretty(f, &amp;<span class="hljs-keyword">self</span>.map)?;
    <span class="hljs-literal">Ok</span>(())
}
</code></pre>
<p>As before, let's see what we are changing here:</p>
<ul>
<li><code>Box&lt;dyn std::error::Error&gt;</code>. This time we return a <a target="_blank" href="https://doc.rust-lang.org/std/boxed/index.html">Box</a> containing a Rust generic error implementation.
To put it simply, a box is a pointer to an allocation in memory.
Since we may return either a file system error when opening the file, or a Serde error when converting it, we don't really know which of the two our function may return. 
Therefore we return a pointer to the possible error, instead of the error itself so that the caller will handle them.</li>
<li>We of course have updated the file name to <code>db.json</code> to match.</li>
<li>Finally we let Serde do the heavy lifting and write our HashMap as a JSON file (pretty printed).</li>
<li>Remember to remove both <code>use std::io::Read;</code> and <code>use std::str::FromStr;</code> from the top of the file as we do not need them anymore.</li>
</ul>
<p>And that's it.
Now you can run your program and inspect the output saved to file. If all went well, you now should see your todos saved as JSON.</p>
<p>You can find the full code written so for in this <a target="_blank" href="https://gist.github.com/Marmiz/541c3ccea832a27bfb60d4882450a4a8">gist</a>.</p>
<h2 id="heading-closing-thoughts-tips-and-additional-resources">Closing Thoughts, Tips and Additional Resources</h2>
<p>This was quite a long journey, and I am honored you have taken it with me.
I hope you learned something and had your curiosity sparked with this introduction. Don't forget that we worked with a very "low-level" language, yet reviewing the code probably felt very familiar to most.</p>
<p>And that is what personally attracts me to Rust – the fact that it empowers me to write code that is both blazing fast and memory efficient without the fear that comes with such responsability: I know that the compiler will be there for me, stopping my code before it is even possible to run it.</p>
<p>Before finishing up, I would like to share with you some additional tips and resources to help you move forward in your Rust journey:</p>
<ul>
<li><a target="_blank" href="https://github.com/rust-lang/rustfmt">Rust fmt</a> Is a very handy tool you can run to format your code following a consistent pattern. No more wasting time configuring your favourite linter plugins.</li>
<li><code>cargo check</code> <a target="_blank" href="https://doc.rust-lang.org/cargo/commands/cargo-check.html">[doc]</a> will attempt to compile your code without running: this is a very useful command when developing, where you just want to check the correctness of the code without actually running it.</li>
<li>Rust comes with both an integrated test suite and a tool to generate documentation: <a target="_blank" href="https://doc.rust-lang.org/cargo/commands/cargo-test.html">cargo test</a> and <a target="_blank" href="https://doc.rust-lang.org/cargo/commands/cargo-rustdoc.html">cargo doc</a>. We didn't touch on them this time, as the tutorial seems rather dense as it is. Perhaps in the future.</li>
</ul>
<p>To learn more about the language, in my opinion the best resources are:</p>
<ul>
<li>The official <a target="_blank" href="https://www.rust-lang.org/">Rust website</a>, where all the information is gathered.</li>
<li>If you like interacting via chat, Rust's <a target="_blank" href="https://discord.gg/rust-lang">Discord</a> server has a very active and helpful community.</li>
<li>If you like learning by reading books, "<a target="_blank" href="https://doc.rust-lang.org/book/title-page.html">The Rust programming language</a>" book is the right choice for you.</li>
<li>If you are more a video type, Ryan Levick's <a target="_blank" href="https://youtu.be/WnWGO-tLtLA">introduction to Rust</a> video series is an amazing resource.</li>
</ul>
<p>You can find the source code of this article hosted on <a target="_blank" href="https://github.com/Marmiz/todo-cli">GitHub</a>.</p>
<p>The cover image comes from <a target="_blank" href="https://rustacean.net/">https://rustacean.net/</a>.</p>
<p>Thanks for reading and Happy Coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Setup Instagram-like Video Stories in Your App ]]>
                </title>
                <description>
                    <![CDATA[ By Agam Mahajan The article will teach you how you can show multiple videos in one view, like we see in Instagram Stories. We'll also learn how to cache the videos in the user's device to help save that user's data and network calls and smooth out th... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/video-stories-and-caching-ios/</link>
                <guid isPermaLink="false">66d45d5cbd438296f45cd377</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ caching ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ video ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 22 Sep 2020 22:01:31 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/09/1_gYkQNP0BaohLJ8hDKL1C6w-1.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Agam Mahajan</p>
<p>The article will teach you how you can show multiple videos in one view, like we see in Instagram Stories.</p>
<p>We'll also learn how to cache the videos in the user's device to help save that user's data and network calls and smooth out their experience.</p>
<p>A quick note: this implementation is for iOS, but the same logic can be applied in other codebases as well.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/ezgif.com-video-to-gif--5-.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In general, whenever we want to play a video, we get the video URL and simply present <code>**AVPlayerViewController**</code> with that URL.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">let</span> videoURL = <span class="hljs-type">URL</span>(string: <span class="hljs-string">"Sample-Video-Url"</span>)
<span class="hljs-keyword">let</span> player = <span class="hljs-type">AVPlayer</span>(url: videoURL!)
<span class="hljs-keyword">let</span> playerViewController = <span class="hljs-type">AVPlayerViewController</span>()
playerViewController.player = player
<span class="hljs-keyword">self</span>.present(playerViewController, animated: <span class="hljs-literal">true</span>) {
    playerViewController.player.play()
}
</code></pre>
<p>Pretty straightforward, right?</p>
<p>But the drawback of this implementation is that you <strong>can’t</strong> <strong>customiz</strong>e it. Which, if you are working for a good product company, will be an everyday ask. :D</p>
<p>Alternatively, we can use <code>**AVPlayerLayer**</code> which will do a similar job – but it allows us to customize the view and other elements.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">let</span> videoURL = <span class="hljs-type">URL</span>(string: <span class="hljs-string">"Sample-Video-Url"</span>)
<span class="hljs-keyword">let</span> player = <span class="hljs-type">AVPlayer</span>(url: videoURL!)
<span class="hljs-keyword">let</span> playerLayer = <span class="hljs-type">AVPlayerLayer</span>(player: player)
playerLayer.frame = <span class="hljs-keyword">self</span>.view.bounds
<span class="hljs-keyword">self</span>.view.layer.addSublayer(playerLayer)
player.play()
</code></pre>
<p>But what if you want to combine multiple videos, similar to <strong>Instagram stories</strong>? Then we probably have to dive in a bit deeper.</p>
<h2 id="heading-coming-back-to-the-problem-statement">Coming Back to the Problem Statement</h2>
<p>Now, let me tell you about my use case.</p>
<p>In my company, Swiggy, we want to be able to show multiple videos, where each video should be shown x number of times.</p>
<p>On top of that, it should have an Instagram-like stories feature.</p>
<ul>
<li>Video-2 should seamlessly autoplay after video-1, and so on</li>
<li>It should jump to corresponding videos whenever the user taps left or right.</li>
</ul>
<p>If you think caching could be the answer, don't worry – I’ll get to that in a bit.</p>
<h3 id="heading-multiple-layers-in-one-view">Multiple layers in one view</h3>
<p>First things first, we need to figure out how to add multiple videos in one view.</p>
<p>What we can do is create one <code>**AVPlayerLayer**</code> and assign the first video to it. When the first video is finished, then we assign the next video to the same <code>**AVPlayerLayer**</code> .</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">addPlayer</span><span class="hljs-params">(player: AVPlayer)</span></span> {
    player.currentItem?.seek(to: <span class="hljs-type">CMTime</span>.zero, completionHandler: <span class="hljs-literal">nil</span>)
    playerViewModel?.player = player
    playerView.playerLayer.player = player
}
</code></pre>
<p>To jump to the previous or next video, we can do the following:</p>
<ul>
<li>Add a tap gesture on the view</li>
<li>If the touch location ‘x’ is less than half of the screen, then assign the previous video, else assign the next video</li>
</ul>
<pre><code class="lang-swift"><span class="hljs-meta">@objc</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">didTapSnap</span><span class="hljs-params">(<span class="hljs-number">_</span> sender: UITapGestureRecognizer)</span></span> {
   <span class="hljs-keyword">let</span> touchLocation = sender.location(ofTouch: <span class="hljs-number">0</span>, <span class="hljs-keyword">in</span>: view)
   <span class="hljs-keyword">if</span> touchLocation.x &lt; view.frame.width/<span class="hljs-number">2</span> {
     changePlayer(forward: <span class="hljs-literal">false</span>)
     } 
   <span class="hljs-keyword">else</span> {
     fillupLastPlayedSnap()
     changePlayer(forward: <span class="hljs-literal">true</span>)
    }
}
</code></pre>
<p>There we go. We now have our own Insta-like Stories video feature.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/13ZwNq4FnbM" 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>
<p>But our task is not done yet!</p>
<h2 id="heading-now-back-to-caching">Now Back to Caching</h2>
<p>We don't want it to be the case that every time a user navigates from one video to another, it starts to download the video from the beginning.</p>
<p>Also, if the video is shown again in the next session, we don't need to do another server call. </p>
<p>If we can cache the video, then the user’s internet will be saved. The load on the server will also be reduced.</p>
<p>Finally, the UX will improve as the user won't have to wait a long time to load the video.</p>
<p><strong>As a good developer, reducing</strong> a <strong>user’s internet usage should be our priority.</strong></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/less-data-usage-happy-customer.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Less data usage, happy customer</em></p>
<h3 id="heading-load-videos-asynchronously">Load Videos <strong>Asynchronously</strong></h3>
<p>The first thing we can use to load videos is <strong>loadValuesAsynchronously</strong>.</p>
<p>According to <a target="_blank" href="https://developer.apple.com/documentation/avfoundation/avasynchronouskeyvalueloading/1387321-loadvaluesasynchronously">the Apple documentation</a>, <strong>loadValuesAsynchronously:</strong></p>
<blockquote>
<p><em>Tells the asset to load the values of all of the specified keys (property names) that are not already loaded.</em></p>
</blockquote>
<p>The advantage here is that it saves the video until it is rendered. So it will not download the video from the start whenever the user navigates to a previous video. It will only download the part which was not rendered earlier.</p>
<p><strong>Let's look at an e</strong>xample<em>**</em>: say we have Video_1 that is 15 seconds long, and the user saw 10 seconds of that video before jumping to Video_2. </p>
<p>Now if the user comes back to Video_1 again by tapping to the left, <strong>loadValuesAsynchronously</strong> will have that 10 seconds of video saved and will only download the remaining (unwatched) 5 seconds.</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">asynchronouslyLoadURLAssets</span><span class="hljs-params">(<span class="hljs-number">_</span> newAsset: AVURLAsset)</span></span> {
    <span class="hljs-type">DispatchQueue</span>.main.async {
            newAsset.loadValuesAsynchronously(forKeys: <span class="hljs-keyword">self</span>.assetKeysRequiredToPlay) {
                <span class="hljs-keyword">for</span> key <span class="hljs-keyword">in</span> <span class="hljs-keyword">self</span>.assetKeysRequiredToPlay {
                    <span class="hljs-keyword">var</span> error: <span class="hljs-type">NSError?</span>
                    <span class="hljs-keyword">if</span> newAsset.statusOfValue(forKey: key, error: &amp;error) == .failed {
                        <span class="hljs-keyword">self</span>.delegate?.playerDidFailToPlay(message: <span class="hljs-string">"Can't use this AVAsset because one of it's keys failed to load"</span>)
                        <span class="hljs-keyword">return</span>
                    }
                }

                <span class="hljs-keyword">if</span> !newAsset.isPlayable || newAsset.hasProtectedContent {
                    <span class="hljs-keyword">self</span>.delegate?.playerDidFailToPlay(message: <span class="hljs-string">"Can't use this AVAsset because it isn't playable or has protected content"</span>)
                    <span class="hljs-keyword">return</span>
                }
                <span class="hljs-keyword">let</span> currentItem = <span class="hljs-type">AVPlayerItem</span>(asset: newAsset)
                <span class="hljs-keyword">let</span> currentPlayer = <span class="hljs-type">AVPlayer</span>(playerItem: currentItem)
                <span class="hljs-keyword">self</span>.delegate?.playerDidSuccesToPlay(playerDetail: currentPlayer)
            }

        }
</code></pre>
<p>You can find more details on <strong>loadValuesAsynchronously</strong> at this <a target="_blank" href="https://developer.apple.com/documentation/avfoundation/avasynchronouskeyvalueloading/1387321-loadvaluesasynchronously">link</a>.</p>
<p>The caveat here is it persists video data for that session only. If the user closes and comes back to the app, the video has to be downloaded again.</p>
<p>So what other options do we have?</p>
<h3 id="heading-saving-videos-in-device">Saving Videos in Device</h3>
<p>Now comes <strong>Video Caching</strong>!</p>
<p>When the video is rendered completely, we can export the video and save it to the user’s device. When the video comes up again in their next session, we can pick the video from the device and simply load it.</p>
<p><strong>AVAssetExportSession</strong><br>According to <a target="_blank" href="https://developer.apple.com/documentation/avfoundation/avassetexportsession">Apple's documentation</a>:</p>
<blockquote>
<p><em>An object that transcodes the contents of an asset source object to create an output of the form described by a specified export preset.</em></p>
</blockquote>
<p>This means that AVAssetExportSession acts as an exporter, through which we can save the file to the user’s device. We have to give the output URL and the output file type.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">let</span> exporter = <span class="hljs-type">AVAssetExportSession</span>(asset: avUrlAsset, presetName: <span class="hljs-type">AVAssetExportPresetHighestQuality</span>)
exporter?.outputURL = outputURL
exporter?.outputFileType = <span class="hljs-type">AVFileType</span>.mp4

exporter?.exportAsynchronously(completionHandler: {
    <span class="hljs-built_in">print</span>(exporter?.status.rawValue)
    <span class="hljs-built_in">print</span>(exporter?.error)
})
</code></pre>
<p>You can find more details on <strong>AVAssetExportSession</strong> at this <a target="_blank" href="https://developer.apple.com/documentation/avfoundation/avassetexportsession">link</a>.</p>
<p>Now the only thing left is to fetch the data from the cache and load the video.</p>
<p>Before loading, check if the video is present in the cache. Then fetch that local URL and give it to <strong>loadValuesAsynchronously.</strong></p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> cacheUrl = <span class="hljs-type">FindCachedVideoURL</span>(forVideoId: videoId) {
    <span class="hljs-keyword">let</span> cacheAsset = <span class="hljs-type">AVURLAsset</span>(url: cacheUrl)
    asynchronouslyLoadURLAssets(cacheAsset)
}
<span class="hljs-keyword">else</span> {
  asynchronouslyLoadURLAssets(newAsset)
}
</code></pre>
<p>Caching will help reduce a lot of user data usage as well as server load (sometimes up to TBs of data).</p>
<h2 id="heading-other-use-cases-for-caching">Other use cases for caching</h2>
<p>What other use cases we can handle with caching? The following are examples of ways you could use caching here:</p>
<h3 id="heading-ensure-optimum-storage">Ensure Optimum Storage</h3>
<p>Before saving the video on the device, you should check whether enough storage is present on the device to do so.</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isStorageAvailable</span><span class="hljs-params">()</span></span> -&gt; <span class="hljs-type">Bool</span> {
   <span class="hljs-keyword">let</span> fileURL = <span class="hljs-type">URL</span>(fileURLWithPath: <span class="hljs-type">NSHomeDirectory</span>() <span class="hljs-keyword">as</span> <span class="hljs-type">String</span>)
   <span class="hljs-keyword">do</span> {
      <span class="hljs-keyword">let</span> values = <span class="hljs-keyword">try</span> fileURL.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey, .volumeTotalCapacityKey])
      <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> totalSpace = values.volumeTotalCapacity,
      <span class="hljs-keyword">let</span> freeSpace = values.volumeAvailableCapacityForImportantUsage <span class="hljs-keyword">else</span> {
          <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
      }
      <span class="hljs-keyword">if</span> freeSpace &gt; minimumSpaceRequired {
         <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
      } <span class="hljs-keyword">else</span> {
          <span class="hljs-comment">// Capacity is unavailable</span>
          <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
      }  
    <span class="hljs-keyword">catch</span> {}
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
}
</code></pre>
<h3 id="heading-remove-deprecated-videos">Remove Deprecated Videos</h3>
<p>You can have a timestamp for each video so that you can clean up old videos from device memory after a certain number of days.</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">cleanExpiredVideos</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">let</span> currentTimeStamp = <span class="hljs-type">Date</span>().timeIntervalSince1970
        <span class="hljs-keyword">var</span> expiredKeys: [<span class="hljs-type">String</span>] = []
        <span class="hljs-keyword">for</span> videoData <span class="hljs-keyword">in</span> videosDict <span class="hljs-keyword">where</span> currentTimeStamp - videoData.value.timeStamp &gt;= expiryTime {
            <span class="hljs-comment">// video is expired. delete</span>
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-number">_</span> = popupVideosDict[videoData.key] {
                expiredKeys.append(videoData.key)
            }
        }
        <span class="hljs-keyword">for</span> key <span class="hljs-keyword">in</span> expiredKeys {
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-number">_</span> = popupVideosDict[key] {
                popupVideosDict.removeValue(forKey: key)
                deleteVideo(<span class="hljs-type">ForVideoId</span>: key)
            }
        }
    }
</code></pre>
<h3 id="heading-maintain-a-limited-number-of-videos">Maintain a limited number of videos</h3>
<p>You can make sure only a limited number of videos are saved in the file at a time. Let's say 10. </p>
<p>Then when the 11th video comes, you can have it delete the least-viewed video and replace it with the new one. This will also help you not consume too much of the user’s device memory.</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">removeVideoIfMaxNumberOfVideosReached</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">if</span> popupVideosDict.<span class="hljs-built_in">count</span> &gt;= maxVideosAllowed {
            <span class="hljs-comment">// remove the least recently used video</span>
            <span class="hljs-keyword">let</span> sortedDict = popupVideosDict.keysSortedByValue { (v1, v2) -&gt; <span class="hljs-type">Bool</span> <span class="hljs-keyword">in</span>
                v1.timeStamp &lt; v2.timeStamp
            }
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> videoId = sortedDict.first <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span>
            }
            popupVideosDict.removeValue(forKey: videoId)
            deleteVideo(<span class="hljs-type">ForVideoId</span>: videoId)
        }
    }
</code></pre>
<h3 id="heading-measure-impact">Measure Impact</h3>
<p>Don’t forget to add logs, so that you can measure the impact of your feature. I have used a custom New Relic Log Event to do so:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">findCachedVideoURL</span><span class="hljs-params">(forVideoId id: String)</span></span> -&gt; <span class="hljs-type">URL?</span> {
        <span class="hljs-keyword">let</span> nsDocumentDirectory = <span class="hljs-type">FileManager</span>.<span class="hljs-type">SearchPathDirectory</span>.documentDirectory
        <span class="hljs-keyword">let</span> nsUserDomainMask = <span class="hljs-type">FileManager</span>.<span class="hljs-type">SearchPathDomainMask</span>.userDomainMask
        <span class="hljs-keyword">let</span> paths = <span class="hljs-type">NSSearchPathForDirectoriesInDomains</span>(nsDocumentDirectory, nsUserDomainMask, <span class="hljs-literal">true</span>)
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> dirPath = paths.first {
            <span class="hljs-keyword">let</span> fileURL = <span class="hljs-type">URL</span>(fileURLWithPath: dirPath).appendingPathComponent(folderPath).appendingPathComponent(id + <span class="hljs-string">".mp4"</span>)
            <span class="hljs-keyword">let</span> filePath = fileURL.path
            <span class="hljs-keyword">let</span> fileManager = <span class="hljs-type">FileManager</span>.<span class="hljs-keyword">default</span>
            <span class="hljs-keyword">if</span> fileManager.fileExists(atPath: filePath) {
                <span class="hljs-type">NewRelicService</span>.sendCustomEvent(with: <span class="hljs-type">NewRelicEventType</span>.statusCodes,
                                                                   eventName: <span class="hljs-type">NewRelicEventName</span>.videoCacheHit,
                                                                   attributes: [<span class="hljs-type">NewRelicAttributeKey</span>.videoSize: fileURL.fileSizeString])
                <span class="hljs-keyword">return</span> fileURL
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
            }
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
    }
</code></pre>
<p>To convert the file size to a readable format, I fetch the file size and convert it to Mbs.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">extension</span> <span class="hljs-title">URL</span> </span>{
    <span class="hljs-keyword">var</span> attributes: [<span class="hljs-type">FileAttributeKey</span> : <span class="hljs-type">Any</span>]? {
        <span class="hljs-keyword">do</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">try</span> <span class="hljs-type">FileManager</span>.<span class="hljs-keyword">default</span>.attributesOfItem(atPath: path)
        } <span class="hljs-keyword">catch</span> <span class="hljs-keyword">let</span> error <span class="hljs-keyword">as</span> <span class="hljs-type">NSError</span> {
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"FileAttribute error: \(error)"</span>)
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
    }

    <span class="hljs-keyword">var</span> fileSize: <span class="hljs-type">UInt64</span> {
        <span class="hljs-keyword">return</span> attributes?[.size] <span class="hljs-keyword">as</span>? <span class="hljs-type">UInt64</span> ?? <span class="hljs-type">UInt64</span>(<span class="hljs-number">0</span>)
    }

    <span class="hljs-keyword">var</span> fileSizeString: <span class="hljs-type">String</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-type">ByteCountFormatter</span>.string(fromByteCount: <span class="hljs-type">Int64</span>(fileSize), countStyle: .file)
    }
}
</code></pre>
<p>This is how you can measure your impact:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/Screenshot-2020-09-16-at-11.34.24-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><strong>Total data saved = n</strong>umber <strong>of request</strong>s <strong><em> video_size = 2.4MB</em>20.3K ~= 49GB</strong></p>
<p>This is just two weeks of data. You do the math for the whole year. ? And this will keep on increasing exponentially over time.</p>
<p>That’s it! You have now built your own caching mechanism.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/yay.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h1 id="heading-wrapping-up">Wrapping up</h1>
<p>In this article, we saw how easily we can integrate multiple videos in one view, giving an Instagram-like story feature.</p>
<p>We also learned why and how caching plays an important role here. We saw how it helps the user save a lot of data and have a smooth user experience.</p>
<p>Do let me know if I missed something, or if you can think of any more use cases.<br>Thanks for your time. :)</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Mobile App That Outsmarts the Competitors ]]>
                </title>
                <description>
                    <![CDATA[ By Emma Coffinet The amount of time people spend on their mobile phones has increased over the years, and so has the number of people using mobile devices. It’s safe to say that mobile has almost completely taken over the desktop. With the number of ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-a-mobile-app-that-outsmarts-the-competitors/</link>
                <guid isPermaLink="false">66d45e3e73634435aafcef72</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 21 Jul 2020 12:54:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/07/image-31-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Emma Coffinet</p>
<p>The amount of time people spend on their mobile phones has increased over the years, and so has the number of people using mobile devices.</p>
<p>It’s safe to say that <a target="_blank" href="https://www.freecodecamp.org/news/the-best-linux-tutorials/">mobile</a> has almost completely taken over the desktop. With the number of users crossing over to mobile, it has become essential to create apps that can provide a seamless and engaging mobile experience.</p>
<p>For a business, there are plenty of ways in which an app can be helpful. Some of these include:</p>
<ul>
<li>Improving sales and revenue generation.</li>
<li>Building a community and increasing engagement by providing the audience with resources.</li>
<li>Improving employee communication with internal business apps.</li>
<li>Improving mobile marketing strategy and increasing brand awareness.</li>
</ul>
<p>Even though there are many positives to it, creating an app can be tedious and intimidating. It can also be costly, risky, and can take a lot of time.</p>
<p>But if you create the app well enough, it will be worth everything in the end. To create a smart mobile app that beats the competition, here are some tips.</p>
<h2 id="heading-define-the-app-objectives">Define the app objectives</h2>
<p>The first step before you even start creating a mobile app is defining your reasons and clearly stating the app’s objectives. </p>
<p>If you don’t have clarity about small details like this, it will affect your planning and app building. In the end, you are not likely to get what you want.</p>
<p>There are two things that you must try to satisfy with your app. First, the ideal goal of users, and second, the purpose of your business. </p>
<p>To determine these, you have to ask yourself specific questions:</p>
<ul>
<li>Which parts of your business do you need to improve?</li>
<li>How can an app help solve the problem?</li>
<li>What are the possible results that you might get?</li>
</ul>
<p>Some other areas of your business that you also have to consider are your budget, timeline, market research, and so on.</p>
<h2 id="heading-state-the-functions-and-features-of-the-app">State the functions and features of the app</h2>
<p>After stating the purpose and objectives of your app clearly, your next step would be to define the <a target="_blank" href="https://mindsea.com/how-to-build-a-mobile-app/">scope of your mobile app</a>. At this point, you start to determine what the app will look like and the features that it will have. </p>
<p>You need to be creative and make a list of necessary functionality and features to achieve your desired results.</p>
<p>Some features that you may include in your app are:</p>
<ul>
<li>eCommerce integrations</li>
<li>Social sharing</li>
<li>Chat</li>
<li>Push notifications</li>
<li>Forms</li>
<li>Contact form</li>
</ul>
<p>Write down all the valuable features and let this guide you through your app development process.</p>
<h2 id="heading-research-app-competition">Research app competition</h2>
<p>Although you already are sure of what you are building and what you need in your app, you might want to look at some of your most successful competitors. Consider what they are doing with their apps and how it is helping them reach similar goals.</p>
<p>Be sure not to look at just your local competition. Research some of the bigger companies in the same industry that reach out to a similar audience in your country or other parts of the world. With this, you can get inspired and get new ideas you can use in the market.</p>
<p>Some of the things that you have to consider are app layout, features, and functionalities. Look out for other things that stand out or things that you might be missing.</p>
<h2 id="heading-plan-the-ux-and-user-journey-of-the-mobile-app">Plan the UX and user journey of the mobile app</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/image-32.png" alt="Image" width="600" height="400" loading="lazy">
<em>UX of an App</em></p>
<p>The success of <a target="_blank" href="https://buildfire.com/how-to-create-a-mobile-app/">mobile apps</a> depends a lot on the User Experience of the app. You have to make sure that your app’s functions align with the users’ desires and expectations. You must plan your User Experience in advance.</p>
<p>If you don’t plan the app’s user experience, you will not have an idea of how complex the app is. You also will not realize how much time you need to invest in developing the app. In the end, you won’t have something tangible to present during user testing. </p>
<p>Make sure that the users have a low UX resistance with the app. The primary goal here is to ensure that they find the solution in the most efficient and intuitive way possible.</p>
<p>If you don’t take the time to plan the UX before you start to build correctly, your users will likely experience difficulty with their use of the app. Then you would need to spend more resources and time to fix things.</p>
<p>The significant difference between a successful app and an unsuccessful one is the user experience. Poor user experience can stem from making some avoidable mistakes when building the app. Some of the mistakes to avoid for good user experience are:</p>
<h3 id="heading-not-understanding-the-needs-of-the-user">Not understanding the needs of the user</h3>
<p>The very foundation for building a good app is understanding what users need. Having an understanding of your audience is crucial. You have to consider the users’ pain points, how your app is better than your competition, and the interface.</p>
<h3 id="heading-adding-too-many-features">Adding too many features</h3>
<p>If it's your first time <a target="_blank" href="https://www.google.com/url?sa=t&amp;source=web&amp;rct=j&amp;url=https://brainiuminfotech.com/blog/mobile-app-development-small-business-get-right/&amp;ved=2ahUKEwjw4MC04c3qAhWJSsAKHehNDVoQFjAKegQIAhAB&amp;usg=AOvVaw0nk8eCEnSAMUERPZjXcsu7">developing a mobile app</a>, you might be tempted to add a lot of features you think are cool. </p>
<p>But this actually relates to a poor user experience most of the time. These features can overwhelm users and make them ditch your app.</p>
<h3 id="heading-creating-poor-and-confusing-navigation">Creating poor and confusing navigation</h3>
<p>No matter how good the onboarding experience is, if users cannot find what they want easily, then your app is less useful. </p>
<p>Your app should have clear navigation that makes it easy for even first time users to do what they want. There are different types of navigation, so you have to choose what you think is the most intuitive for your app.</p>
<p>Other mistakes that you can make that lead to poor user experience are:</p>
<ul>
<li>Neglecting the experience of first-time users.</li>
<li>Overcrowding the user interface</li>
<li>Using jargon and terminology that users don’t understand.</li>
</ul>
<h2 id="heading-launch-the-app">Launch the app</h2>
<p>The last step to <a target="_blank" href="https://www.appypie.com/how-to-create-an-app">creating a mobile app</a> is to launch the app. Following the launch, you should be open to user feedback and improve the app with regular updates based on user experience.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>It takes a lot of time, effort, and resources to create a mobile app. So if you want to create one that outsmarts the competition, you have to do more. It takes a lot of effort, and we’ve highlighted some of the key things you should do in this article. </p>
<p>Whatever it takes, make sure to put the user experience first. Focus on satisfying them and solving their problems with the app, and you are already halfway there.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cordova iOS Application Development Explained from Setup to Deployment ]]>
                </title>
                <description>
                    <![CDATA[ Hybrid Application development for Android is a breeze, be it for development or production configuration. But I personally find Cordova iOS setup, development, and deployment a bit complicated. Most of the Hybrid Application Developers who are in th... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/cordova-ios-application-development-setup-to-deployment/</link>
                <guid isPermaLink="false">66c347e7a1d481faeda49b23</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 01 Jan 2020 20:01:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9e58740569d1a4ca3c99.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><img src="https://image.ibb.co/iKCSuQ/Xz_J197k8_QI32.jpg" alt="iphone_1737513_1920" width="600" height="400" loading="lazy"></p>
<p>Hybrid Application development for Android is a breeze, be it for development or production configuration. But I personally find Cordova iOS setup, development, and deployment a bit complicated.</p>
<p>Most of the Hybrid Application Developers who are in the learning stages are not able to explore hybrid iOS app development process simply because they don't own a mac. And developing iOS apps requires the iOS SDK and XCode (unlike the Android SDK which runs on any Desktop OS). </p>
<p>Therefore the aim of this guide is to show the basic workflow of hybrid iOS app development on a Mac. This way developers can see how it's done even if they can't develop the apps.</p>
<h2 id="heading-creating-a-cordova-project"><strong>Creating a cordova project</strong></h2>
<p>Begin by opening the terminal and creating a new cordova project (use sudo only if you have permission issues, ie. EACCESS errors):</p>
<pre><code class="lang-text">sudo cordova create iosdemo
cd iosdemo
sudo cordova platform add ios
</code></pre>
<p>At the time of writing this guide the cordova iOS platform version is 4.3.1.</p>
<p>We wont modify any source code of the app – rather, we'll simply continue with the default sample code that is added by cordova automatically when we run the create command. However it is assumed we will add plugins modify code in the <code>www</code> folder during normal development flow.</p>
<p>The next step is to run the cordova build command. This will convert our app code to an .xcodeproj file which we will use next.</p>
<pre><code class="lang-text">sudo cordova build ios
</code></pre>
<p>The generated Xcode Project file will be here:</p>
<pre><code class="lang-text">[Your App Folder]/platforms/ios/[Your App Name].xcodeproj
</code></pre>
<p>Now in the case of Android the code signing is done using the Keystore file which is in .jks format. However in iOS it is required that you have a Apple developer account for distributing iOS apps. This is so that we can generate the <em>Certificates</em> and <em>Provisioning Profiles</em> required for distributing the app.</p>
<p>For pricing and other info about a Developer account refer to <a target="_blank" href="https://developer.apple.com/support/purchase-activation/">this page</a>.</p>
<h2 id="heading-creating-development-certificates"><strong>Creating Development Certificates</strong></h2>
<p>Once you have the account ready we can proceed further and login to your <a target="_blank" href="https://developer.apple.com/account/">Apple developer account</a>.</p>
<p>The dashboard screen should look something like this:</p>
<p><img src="https://image.ibb.co/j0d8zQ/Clipboard_image_2017_09_18_11_35_58.png" alt="Project opening in Xcode" width="600" height="400" loading="lazy"></p>
<p>Click on <code>Certificates, Identifiers &amp; Profiles</code>. This should take you to the following screen, which by default displays Certificates issued from your account:</p>
<p><img src="https://image.ibb.co/fk8mm5/1.png" alt="Certificates, Identifiers &amp; Profiles" width="600" height="400" loading="lazy"></p>
<p>iOS Certficates are of mainly two types: Development or Distribution. Click on the Plus (+) button in the top right corner of the list which will open the following page:</p>
<p><img src="https://image.ibb.co/dksXtk/2.png" alt="Add iOS Certificate" width="600" height="400" loading="lazy"></p>
<p>First let's create a development profile. Select <em>iOS App Development</em> and click continue.</p>
<p>This should bring you to the following screen, where you are asked to create and upload a Certificate Signing Request or CSR file.</p>
<p><img src="https://image.ibb.co/iwBE65/3.png" alt="Upload CSR file" width="600" height="400" loading="lazy"></p>
<p>Follow the on-screen instructions to generate it, and continue. Once the certificate is ready, download it to your Mac, and double click it. This will add it to Keychain Access in the Mac.</p>
<p><img src="https://image.ibb.co/dJg6m5/4.png" alt="Download development certificate" width="600" height="400" loading="lazy"></p>
<h2 id="heading-creating-distribution-certificates"><strong>Creating Distribution Certificates</strong></h2>
<p>Creating distribution certificates is similar to the process for creating development certificates. However here we select <code>App Store and Ad Hoc</code> from <code>Production</code> section in the <code>Add iOS Certifcate Page</code>:</p>
<p><img src="https://image.ibb.co/bEKFeQ/5.png" alt="Add iOS Certificate" width="600" height="400" loading="lazy"></p>
<h2 id="heading-creating-the-app-id"><strong>Creating the App ID</strong></h2>
<p>Select <code>App IDs</code> from <code>Identifiers</code> section. This will open the list of existing app IDs. Next click on the Plus button on the top right (+). This will open the <em>Register iOS App IDs</em> page.</p>
<p><img src="https://image.ibb.co/iXTuOk/6.png" alt="Register iOS App IDs" width="600" height="400" loading="lazy"></p>
<p>Select Explicit App ID. The App Description can be any related name – this is what will be displayed in the app id list against the particular app id.</p>
<p>An app id is a string in the format <em>AB11A1ABCD.com.mycompany.myapp</em> where <em>AB11A1ABCD</em> is the app id prefix which is by default the team ID and <em>com.mycompany.myapp</em> is the bundle ID which is unique to each app. </p>
<p>Its recommended that the bundle id must be in a reverse-domain name style string. For example, the company MYCOMPANY may have two apps (App1 and App2). So the HTTP URL for each app is usually app1.mycompany.com and app2.mycompany.com. Hence the bundle IDs for each app will be com.mycompany.app1 and com.mycompany.app2</p>
<p>Next select any services from the checklist that you need to use in your app, such as Push Notifications, Wallet etc. Next click on continue and confirm the details and finally register the app id.</p>
<h2 id="heading-adding-devices-to-your-developer-account"><strong>Adding devices to your developer account</strong></h2>
<p>Select <code>All</code> from the <code>Devices</code> section. This will open the list of already added devices to your Apple developer account. Only these devices are allowed to run the app during development. </p>
<p>To add a new device, click on the Plus button in the top right (+). The following screen will be displayed:</p>
<p><img src="https://image.ibb.co/gTmW3k/8.png" alt="add device screen" width="600" height="400" loading="lazy"></p>
<p>Here the name can be any easily understandable name, for example iPhone 5s ABC Pvt Ltd. The device UDID is the unique ID associated with each Apple device.</p>
<p>To find the UDID of a device follow these steps:</p>
<ol>
<li>Connect the device to your Mac.</li>
<li>Open the System Information app located in the /Applications/Utilities folder.</li>
<li>Select USB under Hardware in the left column. </li>
<li>On the right, select the connected device under USB Device Tree. The device ID, or “Serial Number”, appears below.</li>
</ol>
<p>Once you have entered the device UDID and name click continue, then confirm the details and register.</p>
<h2 id="heading-creating-a-development-provisioning-profile"><strong>Creating a Development Provisioning Profile</strong></h2>
<p>To create a development Provisioning Profile click on Provisioning Profiles -&gt; All. This should show all the profiles, development as well as distribution. Next click on the Plus button on the top right (+) This should show the following page:</p>
<p><img src="https://image.ibb.co/dk3KOk/7.png" alt="Creating a development provisioning profile" width="600" height="400" loading="lazy"></p>
<p>Here select <code>iOS App Development</code> and click continue. In the dropdown that is displayed select the App ID we created previously and continue.</p>
<p>Next A checklist of certificates is displayed from which we can select one or multiple. These are development certificates and not distribution ones. The generated provisioning profile will be linked to these certificates.</p>
<p>When you click Continue, a checklist of devices is displayed. Select one, multiple, or all. Only selected devices will be allowed to run the app using this provisioning profile.</p>
<p>Next, after clicking continue, enter the name for the provisioning profile, and download the generated .mobileprovision file.</p>
<p><strong>Notes</strong>: it's the same process to create your Adhoc Distribution Provisioning Profile. It's also very similar to create your AppStore Distribution Provisioning Profile, except for that one we don't select devices, as the app will be available publicly through the AppStore.</p>
<p>Now that we have all that we need we can continue generating the actual ipa using Xcode.</p>
<p><em>Cordova build command converts our app code to an xcode project. Using Xcode we create an .ipa file which is the actual app to be installed.</em></p>
<p>Before moving forward double tap on both Certificates to add them to your keychain.</p>
<h2 id="heading-continuing-in-xcode"><strong>Continuing in Xcode</strong></h2>
<p>Next, double tap the .xcodeproj file which should open it in Xcode. (Please use the latest version of Xcode – I have used Xcode 8.3.2.)</p>
<p><img src="https://image.ibb.co/mPdGKQ/Screen_Shot_2017_09_18_at_11_06_55_AM.png" alt="Project opening in Xcode" width="600" height="400" loading="lazy"></p>
<p>The Xcode screen should look something like the above.</p>
<p>Click on the App Name on the top left corner fo the window. This will open the detailed view on the right side.</p>
<p><img src="https://image.ibb.co/fqb3ZQ/Screen_Shot_2017_09_18_at_5_07_53_PM.png" alt="Project settings" width="600" height="400" loading="lazy"></p>
<p>Then click on Targets-&gt; App Name:</p>
<p><img src="https://image.ibb.co/i0znTk/Screen_Shot_2017_09_18_at_5_11_28_PM.png" alt="targets" width="600" height="400" loading="lazy"></p>
<p>This will display the following details tab:</p>
<p><img src="https://image.ibb.co/ksBj8k/Screen_Shot_2017_09_18_at_5_15_29_PM.png" alt="target details" width="600" height="400" loading="lazy"></p>
<p>Click on general, which should display this:</p>
<p><img src="https://image.ibb.co/k8KFEQ/Screen_Shot_2017_09_18_at_5_18_29_PM.png" alt="general details" width="600" height="400" loading="lazy"></p>
<p>Uncheck the Automatically Manage Signing Checkbox.</p>
<p>This should display the following error, stating AppNAme requires a provisioning profile:</p>
<p><img src="https://image.ibb.co/mDq5EQ/Screen_Shot_2017_09_18_at_5_20_35_PM.png" alt="profile error" width="600" height="400" loading="lazy"></p>
<p>Next, under Signing (Debug), click the Provisioning Profile Dropdown and select the <em>import profile</em> option. In the file selection dialog that pops up, navigate to the path where the development provisioning profile is downloaded, and select it. It will have an extension of <em>.mobileprovision.</em></p>
<p>After you select that, the error should be gone, and it should show Team as the Team Name in your Apple developer account and Signing Certificate Name.</p>
<p>Do the same thing for the Signing (Release) section – but in the file selection dialog select the Ad Hoc distribution Profile.</p>
<p>Now that the Code signing steps are done we either</p>
<ul>
<li>run the app directly on device</li>
<li>run the app on a simulator</li>
<li>generate an ipa file for distribution</li>
<li>upload app to appstore</li>
</ul>
<h2 id="heading-running-the-app-directly-on-device"><strong>Running the app directly on device</strong></h2>
<p>To run the app on a device connect the device to the Mac via USB. Then in the top left corner in the list of devices select the connected device, and click the run or play button (black triangular button):</p>
<p><img src="https://image.ibb.co/k4xo15/Screen_Shot_2017_09_18_at_5_34_14_PM.png" alt="run device" width="600" height="400" loading="lazy"></p>
<p><img src="https://image.ibb.co/hjzhuQ/Screen_Shot_2017_09_18_at_5_36_55_PM.png" alt="run device" width="600" height="400" loading="lazy"></p>
<p>The build status will be displayed in the status bar on the top of the window. If all goes fine, the app should be installed on the device, and it should automatically load in a while.</p>
<p><strong>Note</strong>: the steps are the same for running the app on a simulator. But instead of an actual device we use the available iPhone and iPad simulators from the device list.</p>
<h2 id="heading-generate-an-ipa-file-for-distribution"><strong>Generate an ipa file for distribution</strong></h2>
<p>This approach can be done in case you need to distribute the app to the testing team, etc. However the device used by them must have a UDID present in the provisioning profile.</p>
<p>From the Xcode menu select <code>Product</code> -&gt; <code>Clean</code>, then <code>Product</code> -&gt; <code>Archive</code>. The Archives organizer appears and displays the new archive.</p>
<p><img src="https://image.ibb.co/iunfMG/6_ios_archive_organizer_2x.png" alt="ios archive organizer" width="600" height="400" loading="lazy"></p>
<p>In the righthand side panel select the Export option and a list of options will appear.</p>
<p>To distribute your app to users with designated devices, select “Save for Ad Hoc Deployment.” The app will be code signed with the distribution certificate.</p>
<p>To distribute your app for internal testing, select “Save for Development Deployment.” The app will be code signed with your development certificate.</p>
<p><img src="https://image.ibb.co/jQJLMG/6_ios_createappstorepackage_1_2x.png" alt="ios archive organizer export as ad hoc" width="600" height="400" loading="lazy"></p>
<p>In the dialog that appears, choose a team from the pop-up menu and click Choose.</p>
<p><img src="https://image.ibb.co/gH2VMG/6_ios_export_choose_team_2x.png" alt="ios export select team" width="600" height="400" loading="lazy"></p>
<p>Next the device selection dialog pops up. Select either <em>All devices</em> or <em>specific devices</em> and click next.</p>
<p>Next the review dialog is displayed. Here it will show the signing certificate and provisioning profile used for generating the build. Review and click next. Finally the file save as a popup is displayed to select the location in the file system to store the exported app file.</p>
<p>The app is exported as .ipa` file .</p>
<p>To run this file on device simply double tap it which will open it in iTunes.</p>
<p>Then connect your device (this should show a small device icon on the top left corner of the iTunes window). Tapping on it will show the device summary such as apps, music etc on the device. Select the apps tab, and in the left pane select the app to be installed and click install. Wait for the process to complete and click apply. This should install the ipa file on your device.</p>
<p>To debug the app:</p>
<ol>
<li>open Safari</li>
<li>open the app on the device</li>
<li>in the Safari menu bar select <code>Develop --&gt; Your Device Name --&gt; Your App</code>.</li>
</ol>
<h2 id="heading-thats-all-folks"><strong>Thats all folks!</strong></h2>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to programmatically build a Spotify clone for iOS using AutoLayout: adding photos and updating the UI ]]>
                </title>
                <description>
                    <![CDATA[ By Said Hayani This is the second part of an article on building a Spotify UI clone with autoLayout programmatically. If you missed the first part, no worries - just please go and check it now.  In this article, we are going to add some mocked pictur... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-spotify-clone-for-ios-with-autolayout-programmatically-part-2/</link>
                <guid isPermaLink="false">66d460d2868774922c885008</guid>
                
                    <category>
                        <![CDATA[ 100DaysOfCode ]]>
                    </category>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ autolayout ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS13 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iphone ]]>
                    </category>
                
                    <category>
                        <![CDATA[ learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ learning to code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ programing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                    <category>
                        <![CDATA[ User Interface ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 10 Dec 2019 03:44:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/12/featured_image-4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Said Hayani</p>
<p>This is the second part of an article on building a Spotify UI clone with autoLayout programmatically. If you missed the first part, no worries - just please go and <a target="_blank" href="https://www.freecodecamp.org/news/autolayout-programmatically-spotify-clone-in-swift/">check it now</a>. </p>
<p>In this article, we are going to add some mocked pictures and try to make the UI look the same as Spotify's.</p>
<p>This is what we are going to do today ?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-09-at-9.55.19-PM-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This is were we left off in the first part:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/complet-layout-demo1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The next step is to create customized cells. So let's start by creating one with the name  <code>SubCustomCell</code>.</p>
<p>First, create a new Swift file inside the project folder and name it <code>SubCustomCell.swift</code>. This file will contain our custom cell that will represent the Playlist. After creating the file, try to add in the code below and initialize the cell, maybe with <code>backgroundColor</code>,  to see the UI changes when we register the cell with the <code>collectionView</code>. </p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> UIKit

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SubCustomCell</span>: <span class="hljs-title">UICollectionViewCell</span> </span>{
        <span class="hljs-keyword">override</span> <span class="hljs-keyword">init</span>(frame: <span class="hljs-type">CGRect</span>) {
        <span class="hljs-keyword">super</span>.<span class="hljs-keyword">init</span>(frame: frame)
        backgroundColor = .red
    }

    <span class="hljs-keyword">required</span> <span class="hljs-keyword">init</span>?(coder aDecoder: <span class="hljs-type">NSCoder</span>) {
        <span class="hljs-built_in">fatalError</span>(<span class="hljs-string">"init(coder:) has not been implemented"</span>)
    }
}
</code></pre>
<p>Then we register the <code>SubCustomCell</code>  inside <code>CustomCell.swift</code> within the <code>init</code> block. Replace <code>UICollectionViewCell.self</code> with  <code>SubCustomCell</code> like below.</p>
<pre><code class="lang-swift"> collectionView.register(<span class="hljs-type">SubCustomCell</span>.<span class="hljs-keyword">self</span>, forCellWithReuseIdentifier: cellId)
</code></pre>
<p>Also we need to make a modification on the <code>cellForItemAt</code> method and make it conform to  <code>SubCustomCell</code> like the following.</p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UICollectionViewCell</span> {
        <span class="hljs-keyword">let</span> cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, <span class="hljs-keyword">for</span>: indexPath) <span class="hljs-keyword">as</span>! <span class="hljs-type">SubCustomCell</span>
        <span class="hljs-comment">// cell.backgroundColor = .yellow</span>

        <span class="hljs-keyword">return</span> cell
    }
</code></pre>
<p>You should see the <code>backgroundColor</code> changed to <code>red</code> .</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-03-at-1.10.25-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Swift CustomCell</em></p>
<p>Up until this point everything should be straightforward and clear.</p>
<p>Now we're going to fill the cells with some mocked pictures and create an <code>ImageView</code> inside each cell. I already downloaded some random pictures from <a target="_blank" href="https://www.pexels.com/">pexels.com,</a> but feel free to use any pictures you like (including these). You can find them in the <a target="_blank" href="https://github.com/hayanisaid/autoLayout-programmatically-in-swift">project files on Github</a>.</p>
<p>Let's create the <code>UIImageView</code> inside <code>SubCustomCell.swift</code> and make some constraints.</p>
<pre><code class="lang-swift">    <span class="hljs-keyword">let</span> <span class="hljs-type">ImageView</span> : <span class="hljs-type">UIImageView</span> = {
       <span class="hljs-keyword">let</span> iv = <span class="hljs-type">UIImageView</span>()
        iv.backgroundColor = .yellow
        <span class="hljs-keyword">return</span> iv

    }()
</code></pre>
<p>And add it to the <code>view</code> within the <code>init</code> block using <code>addSubView</code>.</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">override</span> <span class="hljs-keyword">init</span>(frame: <span class="hljs-type">CGRect</span>) {
        <span class="hljs-keyword">super</span>.<span class="hljs-keyword">init</span>(frame: frame)
        addSubview(<span class="hljs-type">ImageView</span>)

    }
</code></pre>
<p>Now let's make the <code>ImageView</code> take up all the space within the cell with the constraints below.</p>
<pre><code class="lang-swift"> <span class="hljs-type">ImageView</span>.translatesAutoresizingMaskIntoConstraints = <span class="hljs-literal">false</span>
            <span class="hljs-type">ImageView</span>.topAnchor.constraint(equalTo: topAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.leftAnchor.constraint(equalTo: leftAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.rightAnchor.constraint(equalTo: rightAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = <span class="hljs-literal">true</span>
</code></pre>
<ul>
<li><code>LeftAnchor</code> represents the left anchor of the cell</li>
<li><code>rightAnchor</code> represents the right anchor of the cell</li>
<li><code>bottomAnchor</code> represents the bottom anchor of the cell </li>
<li><code>topAnchor</code> represents the top anchor of the cell</li>
</ul>
<p>And by making <code>ImageView</code> 's top anchor equal to the cell's top anchor (and doing the same for <code>ImageView</code> 's left, right, and bottom anchor) it makes the <code>ImageView</code> take up all the space of the <code>SubCustomCell</code> (cell).</p>
<p>Note: first you need to use <code>translatesAutoresizingMaskIntoConstraints</code> to be able to apply the constraints to the elements. Also don't forget to call <code>isActive</code> property and assign it to <code>true</code> – without doing that the constraints won't work and nothing will change.</p>
<p>The <code>ImageView</code> should have an image, so let's add one.</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">let</span> <span class="hljs-type">ImageView</span> : <span class="hljs-type">UIImageView</span> = {
       <span class="hljs-keyword">let</span> iv = <span class="hljs-type">UIImageView</span>()
        iv.backgroundColor = .yellow
        <span class="hljs-comment">// we have &gt;image1&lt; file inside the project </span>
        iv.image = <span class="hljs-type">UIImage</span>(named: <span class="hljs-string">"image1"</span>)
        iv.contentMode = .scaleAspectFill
        iv.clipsToBounds = <span class="hljs-literal">true</span>

        <span class="hljs-keyword">return</span> iv

    }()
</code></pre>
<p>And if you build and run the app, you should see the results and picture we added to the <code>SubCustomCell</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-03-at-1.37.51-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Cool ?. Now there is an element we should add to the <code>SubCustomCell</code> to finish up. We need a title that will represent the title of the playlist:  <code>UILabel</code>.</p>
<p>For the title it will be like this:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">let</span> <span class="hljs-type">TitleLabel</span> : <span class="hljs-type">UILabel</span> = {
        <span class="hljs-keyword">let</span> lb = <span class="hljs-type">UILabel</span>()
        lb.textColor = <span class="hljs-type">UIColor</span>.lightGray
        lb.font = <span class="hljs-type">UIFont</span>.systemFont(ofSize: <span class="hljs-number">16</span>)
        lb.font = <span class="hljs-type">UIFont</span>.boldSystemFont(ofSize: <span class="hljs-number">20</span>)
        lb.text = <span class="hljs-string">"Evening Music"</span>

        <span class="hljs-keyword">return</span> lb
    }()
</code></pre>
<p>I just put some random text there – you can put whatever you like. The next step is to add the element to the view and give it some constraints. The title will be placed at the bottom of the <code>ImageView</code>.</p>
<h3 id="heading-add-to-view">Add to view:</h3>
<pre><code class="lang-swift">addSubview(<span class="hljs-type">TitleLabel</span>)
</code></pre>
<h3 id="heading-applying-the-constraints-for-both-the-imageview-and-the-titlelabel">Applying the constraints for both the <code>ImageView</code> and the <code>TitleLabel</code></h3>
<pre><code class="lang-swift"> <span class="hljs-type">ImageView</span>.translatesAutoresizingMaskIntoConstraints = <span class="hljs-literal">false</span>
            <span class="hljs-type">ImageView</span>.topAnchor.constraint(equalTo: topAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.leftAnchor.constraint(equalTo: leftAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.rightAnchor.constraint(equalTo: rightAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.heightAnchor.constraint(equalToConstant: <span class="hljs-number">240</span>).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.bottomAnchor.constraint(equalTo: <span class="hljs-type">TitleLabel</span>.topAnchor).isActive = <span class="hljs-literal">true</span>



            <span class="hljs-type">TitleLabel</span>.translatesAutoresizingMaskIntoConstraints = <span class="hljs-literal">false</span>
            <span class="hljs-type">TitleLabel</span>.topAnchor.constraint(equalTo: <span class="hljs-type">ImageView</span>.bottomAnchor,constant: <span class="hljs-number">10</span>).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">TitleLabel</span>.leftAnchor.constraint(equalTo: leftAnchor, constant: <span class="hljs-number">5</span>).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">TitleLabel</span>.rightAnchor.constraint(equalTo: rightAnchor, constant: -<span class="hljs-number">5</span>).isActive = <span class="hljs-literal">true</span>
</code></pre>
<p>And here we go!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-06-at-1.45.10-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We made the picture take up most of the space in the cell, and the rest is taken up by the title. As you can see, you can scroll horizontally in each section and also vertically in the entire screen.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/demo2.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now we are put some mock data into the cells to make it feel like it's real. For that I created a <code>JSON</code> file that contains some random data for sections and playlists.</p>
<p>First let's create a two structs, <code>Section</code> and <code>Playlist</code> . We create a separate file for each struct. </p>
<p> <code>section.swift</code> </p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> Foundation
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Section</span> </span>{
    <span class="hljs-keyword">var</span> title : <span class="hljs-type">String</span>
    <span class="hljs-keyword">var</span> playlists : <span class="hljs-type">NSArray</span>
    <span class="hljs-keyword">init</span>(dictionary:[<span class="hljs-type">String</span> : <span class="hljs-type">Any</span>]) {
        <span class="hljs-keyword">self</span>.title = dictionary[<span class="hljs-string">"title"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">String</span> ?? <span class="hljs-string">""</span>
        <span class="hljs-keyword">self</span>.playlists = dictionary[<span class="hljs-string">"playlists"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">NSArray</span> ?? []

}
}
</code></pre>
<p><code>playlist.swift</code></p>
<pre><code class="lang-swift"><span class="hljs-comment">//</span>
<span class="hljs-comment">//  playlist.swift</span>
<span class="hljs-comment">//  spotifyAutoLayout</span>
<span class="hljs-comment">//</span>
<span class="hljs-comment">//  Created by admin on 12/6/19.</span>
<span class="hljs-comment">//  Copyright © 2019 Said Hayani. All rights reserved.</span>
<span class="hljs-comment">//</span>

<span class="hljs-keyword">import</span> Foundation
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">PlayList</span> </span>{
    <span class="hljs-keyword">var</span> title: <span class="hljs-type">String</span>
    <span class="hljs-keyword">var</span> image : <span class="hljs-type">String</span>
    <span class="hljs-keyword">init</span>(dictionary : [<span class="hljs-type">String</span> : <span class="hljs-type">Any</span>]) {
        <span class="hljs-keyword">self</span>.title = dictionary[<span class="hljs-string">"title"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">String</span> ?? <span class="hljs-string">""</span>
        <span class="hljs-keyword">self</span>.image = dictionary[<span class="hljs-string">"image"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">String</span> ?? <span class="hljs-string">""</span>
    }

}
</code></pre>
<p>And then inside <code>ViewController.swift</code> we create a function that fetches the JSON for us and stores the results in an array.</p>
<pre><code class="lang-swift">
        <span class="hljs-built_in">print</span>(<span class="hljs-string">"attempt to fetch Json"</span>)
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> path = <span class="hljs-type">Bundle</span>.main.path(forResource: <span class="hljs-string">"test"</span>, ofType: <span class="hljs-string">"json"</span>) {
            <span class="hljs-keyword">do</span> {
                  <span class="hljs-keyword">let</span> data = <span class="hljs-keyword">try</span> <span class="hljs-type">Data</span>(contentsOf: <span class="hljs-type">URL</span>(fileURLWithPath: path), options: .mappedIfSafe)
                  <span class="hljs-keyword">let</span> jsonResult = <span class="hljs-keyword">try</span> <span class="hljs-type">JSONSerialization</span>.jsonObject(with: data, options: .mutableLeaves)
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> jsonResult = jsonResult <span class="hljs-keyword">as</span>? [ <span class="hljs-type">Any</span>] {
                            <span class="hljs-comment">// do stuff</span>
                    jsonResult.forEach { (item) <span class="hljs-keyword">in</span>

                        <span class="hljs-keyword">let</span> section = <span class="hljs-type">Section</span>(dictionary: item <span class="hljs-keyword">as</span>! [<span class="hljs-type">String</span> : <span class="hljs-type">Any</span>])
                       <span class="hljs-comment">// print("FEtching",section.playlists)</span>
                        <span class="hljs-keyword">self</span>.sections.append(section)
                    }


                  <span class="hljs-keyword">self</span>.collectionView.reloadData()
                  }
              } <span class="hljs-keyword">catch</span> {
                   <span class="hljs-comment">// handle error</span>
              }
        }
    }
</code></pre>
<p>The <code>fetchJson</code> function is called within the <code>ViewDidLoad</code> method. We also have a variable called <code>sections</code> where we store the results:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> sections = [<span class="hljs-type">Section</span>]()
</code></pre>
<p>The next step is to pass the data from <code>ViewController</code> to <code>CustomCell</code>. For that we create a variable inside <code>CustomCell</code> which will receive the data for each section: </p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> section : <span class="hljs-type">Section?</span>{
        <span class="hljs-keyword">didSet</span>{
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"section ✅"</span>,<span class="hljs-keyword">self</span>.section)
        }
    }
</code></pre>
<p>We use <code>cellForItemAt</code>  inside the <code>ViewController</code> method to pass the data directly to the <code>CustomCell</code> .</p>
<pre><code class="lang-swift"><span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UICollectionViewCell</span> {
        <span class="hljs-keyword">let</span> cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, <span class="hljs-keyword">for</span>: indexPath) <span class="hljs-keyword">as</span>! <span class="hljs-type">CustomCell</span>

        cell.section = sections[indexPath.item]

        <span class="hljs-keyword">return</span> cell
    }
</code></pre>
<p>Note: we always call <strong><code>self</code></strong><code>.collectionView.reloadData()</code> every-time <code>fetchJson</code> is called so the block below, inside <code>CustomCell</code>, will be called as well. Check the console, <code>shift</code> + command + C:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> section : <span class="hljs-type">Section?</span> {
        <span class="hljs-keyword">didSet</span>{
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"section ✅"</span>,<span class="hljs-keyword">self</span>.section)
        }
    }
</code></pre>
<p>The first thing we change is to set the the section title:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> section : <span class="hljs-type">Section?</span> {
        <span class="hljs-keyword">didSet</span>{
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"section ✅"</span>,<span class="hljs-keyword">self</span>.section)
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> section = <span class="hljs-keyword">self</span>.section <span class="hljs-keyword">else</span> {<span class="hljs-keyword">return</span>}
            <span class="hljs-keyword">self</span>.titleLabel.text = section.title
        }
    }
</code></pre>
<p>And then you should see that each section has a specific title on the screen ?.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-06-at-3.23.32-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now it's time to pass the data down to <code>SubCustomCell</code>. We do the same thing as we did above. We need to pass the <code>playlists</code> array, so we create a variable named <code>playlists</code> inside <code>CustomCell</code>.</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> playlists : [<span class="hljs-type">PlayList</span>]() <span class="hljs-comment">//empty</span>
</code></pre>
<p>First, we map through the <code>playlists</code>  from the <code>JSON</code>. Then we add each playlist with the <code>playlists</code> var.</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> section : <span class="hljs-type">Section?</span> {
        <span class="hljs-keyword">didSet</span>{
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"section ✅"</span>,<span class="hljs-keyword">self</span>.section)
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> section = <span class="hljs-keyword">self</span>.section <span class="hljs-keyword">else</span> {<span class="hljs-keyword">return</span>}
            <span class="hljs-keyword">self</span>.titleLabel.text = section.title
            <span class="hljs-comment">// append to playlists array</span>
             <span class="hljs-keyword">self</span>.section?.playlists.forEach({ (item) <span class="hljs-keyword">in</span>
                <span class="hljs-keyword">let</span> playlist = <span class="hljs-type">PlayList</span>(dictionary: item <span class="hljs-keyword">as</span>! [<span class="hljs-type">String</span> : <span class="hljs-type">Any</span>])
                <span class="hljs-keyword">self</span>.playlists.append(playlist)

            })
            <span class="hljs-keyword">self</span>.collectionView.reloadData()
        }
    }
</code></pre>
<p>Attention! If you try to run the app it may crash. This is because we forgot to set the number of sections. Since we are now receiving the data from JSON, the number should be dynamic based on the number of sections we have. The number of sections should be equal to the number of sections inside the <code>JSON</code>, so we need to modify <code>numberOfItemsInSection</code> inside <code>ViewController</code> to the below :</p>
<pre><code class="lang-swift">   <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, numberOfItemsInSection section: Int)</span></span> -&gt; <span class="hljs-type">Int</span> {
        <span class="hljs-keyword">return</span> sections.<span class="hljs-built_in">count</span>
    }
</code></pre>
<p>We do the same thing with the same method inside <code>CustomCell.swift</code> – but here we consider the number of the <code>playlists</code> instead.</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, numberOfItemsInSection section: Int)</span></span> -&gt; <span class="hljs-type">Int</span> {
        <span class="hljs-keyword">return</span>  <span class="hljs-keyword">self</span>.playlists.<span class="hljs-built_in">count</span>
    }
</code></pre>
<p>The last step we have to complete is to pass each single playlist <code>Object</code> to <code>SubCustomCell</code> within <code>cellForItemAt</code> in <code>CustomCell.swift</code>. </p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UICollectionViewCell</span> {
        <span class="hljs-keyword">let</span> cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, <span class="hljs-keyword">for</span>: indexPath) <span class="hljs-keyword">as</span>! <span class="hljs-type">SubCustomCell</span>
        <span class="hljs-comment">// here ?</span>
        cell.playlist = playlists[indexPath.item]
        <span class="hljs-keyword">return</span> cell
    }
</code></pre>
<p>And we are going to get that data inside <code>SubCustomCell</code> via the <code>playlist</code> variable and finally display the title and image of the playlist.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">var</span> playlist : <span class="hljs-type">PlayList?</span> {
           <span class="hljs-keyword">didSet</span>{
               <span class="hljs-built_in">print</span>(<span class="hljs-string">"Playlist ?"</span>,<span class="hljs-keyword">self</span>.playlist)
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> playlist = <span class="hljs-keyword">self</span>.playlist <span class="hljs-keyword">else</span> {<span class="hljs-keyword">return</span>}
            <span class="hljs-comment">// The Image ?</span>
            <span class="hljs-keyword">self</span>.<span class="hljs-type">ImageView</span>.image = <span class="hljs-type">UIImage</span>(named: playlist.image)
            <span class="hljs-comment">// the playlist title ?</span>
            <span class="hljs-keyword">self</span>.<span class="hljs-type">TitleLabel</span>.text = <span class="hljs-keyword">self</span>.playlist?.title

           }
       }
</code></pre>
<p>I think everything should work fine now, just as below ?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/demo3.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p> One last update to the UI: we have to add some padding and margins to the <code>section</code>  and <code>playlist</code> titles and make the playlist a little bit smaller.</p>
<p>Let's first add some padding for the section titles. To do that, we need just to give the <code>constant</code> property some number value inside the section cell <code>CustomCell</code> and within <code>setupSubCells</code>: </p>
<pre><code class="lang-swift"> collectionView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor,constant: <span class="hljs-number">15</span>).isActive = <span class="hljs-literal">true</span>
</code></pre>
<p>And if you see the entire <code>collectionView</code> come in at the bottom of the <code>titleLabel</code>, all we need to do is add more space by adding <code>15</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/paddingForTitles-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Next we come to the title of the <code>playlist</code>. This will be inside <code>SubCustomCell</code>, and we just need to add more space at the bottom of the ImageView.</p>
<pre><code class="lang-swift"> <span class="hljs-type">ImageView</span>.bottomAnchor.constraint(equalTo: <span class="hljs-type">TitleLabel</span>.topAnchor,constant: -<span class="hljs-number">15</span>).isActive = <span class="hljs-literal">true</span>
</code></pre>
<p>We already have the constant there. In order for it to work, the value should be <code>-15</code></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/demo4.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Finally the playlist needs to be a little bit smaller. This is easy: we just make the <code>playlist</code> cell's height and width equal to the <code>section</code> cell's height divided by 2, just like below:</p>
<p><code>CustomCell.swift</code></p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">CGSize</span> {

        <span class="hljs-keyword">let</span> width = frame.height / <span class="hljs-number">2</span>
        <span class="hljs-keyword">let</span> height = frame.height / <span class="hljs-number">2</span>

        <span class="hljs-keyword">return</span> <span class="hljs-type">CGSize</span>(width: width, height: height)

    }
</code></pre>
<p>Make the ImageView's height equal to <code>150</code> as well.</p>
<pre><code class="lang-swift">  <span class="hljs-comment">//SubCutomCell.swift</span>
  <span class="hljs-type">ImageView</span>.heightAnchor.constraint(equalToConstant: <span class="hljs-number">150</span>).isActive = <span class="hljs-literal">true</span>
</code></pre>
<p>And here we go ?.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-09-at-9.55.19-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Perfect! I think that's enough for today – I don't want to make this article too long. So we will have another part where we will add the <code>TabBar</code> and the description, as well as some icons for the playlist.</p>
<p><strong>View the</strong> <a target="_blank" href="https://github.com/hayanisaid/autoLayout-programmatically-in-swift"><strong>Full source code on GitHub</strong></a><strong>?.</strong></p>
<p>Thanks for your time. I hope I haven't missed anything. If I did please @mention me on <a target="_blank" href="https://twitter.com/SaidHYN">Twitter</a>, or if you have any questions or an addition to this post the doors are always open to anyone. Thanks??.</p>
<p><strong><a target="_blank" href="https://webege.us16.list-manage.com/subscribe?u=311846a57d1e1a666287ad128&amp;id=2b386b2ebb">Subscribe</a></strong> <em>to my email list to be notified when the third part of this tutorial is published.</em> </p>
<blockquote>
<p>By the way, I’ve recently worked with a strong group of software engineers for one of my mobile applications. The organization was great, and the product was delivered very quickly, much faster than other firms and freelancers I’ve worked with, and I think I can honestly recommend them for other projects out there. Shoot me an email if you want to get in touch — <a target="_blank" href="mailto:said@devsdata.com">said@devsdata.com</a>.</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
