<?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[ Sharvin Shah - 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[ Sharvin Shah - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 09 May 2026 16:24:36 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/Sharvin26/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Custom AI Chat Application with Next.js: Fine-Tune GPT Using Your Data ]]>
                </title>
                <description>
                    <![CDATA[ In 2025, AI-powered applications have advanced from generic chatbots to highly specialised assistants that understand your specific field, communicate in your style, and give contextually relevant answers. While Large Language Models (LLMs) like GPT-... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-custom-ai-chat-application-with-nextjs/</link>
                <guid isPermaLink="false">68e4f54b40f8bf1b48305e00</guid>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Chat ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sharvin Shah ]]>
                </dc:creator>
                <pubDate>Tue, 07 Oct 2025 11:11:07 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1759834368425/fc26010c-077e-4af9-86cd-e16f1c218560.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In 2025, AI-powered applications have advanced from generic chatbots to highly specialised assistants that understand your specific field, communicate in your style, and give contextually relevant answers. While Large Language Models (LLMs) like GPT-5 have impressive general abilities, there is an increasing demand for AI that deeply understands particular businesses, personal brands, or specialised areas of knowledge.</p>
<p>Imagine having an AI assistant that not only knows about web development in general but also understands your specific coding style, knows your project history, and can answer questions in your voice. This isn't science fiction - it's what fine-tuning makes possible today.</p>
<p>In this tutorial, you'll learn how to fine-tune OpenAI's latest GPT-4.1 models and create a production-ready chat application using Next.js 15. I will guide you through the entire process: from preparing your dataset and submitting it for fine-tuning, to building a sleek chat interface that uses your custom model.</p>
<p>I'll show you this process using content from my agency website, mtechzilla.com, as example data. You'll learn how to scrape, clean, and format real-world content for training. Naturally, you'll want to use your own data - whether it's documentation, blog posts, customer support transcripts, or any other text that reflects the knowledge and style you want your AI to have.</p>
<p>This tutorial is for developers who are familiar with React and Node.js but are new to fine-tuning AI models. By the end, you'll have a fully functional, custom AI chat application ready to deploy.</p>
<p>As of September 2025, fine-tuning GPT-5 is not supported yet. This tutorial uses GPT-4.1. When GPT-5 fine-tuning becomes available, you'll mainly need to change the base model name.</p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-understanding-fine-tuning">Understanding Fine-Tuning</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-1-dataset-preparation">Step 1: Dataset Preparation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-fine-tuning-submission">Step 2: Fine-Tuning Submission</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-nextjs-application-setup">Step 3: Next.js Application Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-building-the-chat-interface">Step 4: Building the Chat Interface</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-api-route-integration">Step 5: API Route Integration</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-6-testing-your-application">Step 6: Testing Your Application</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-understanding-fine-tuning">Understanding Fine-Tuning</h2>
<p>Before we jump into the code, let's explain what fine-tuning really means and when it's the best option for your project.</p>
<p>Fine-tuning means taking a pre-trained language model and training it further with your specific dataset. It's like teaching a smart student about your particular area of expertise and communication style. The model retains its general knowledge but becomes specialised in your field.</p>
<p>This is quite different from other methods of customising AI behavior. Retrieval-Augmented Generation (RAG) involves providing relevant context to the model when a query is made, similar to giving someone reference materials to use while answering questions. Prompt engineering, on the other hand, involves creating smart instructions to direct the model's behavior without any additional training. Fine-tuning, however, results in a model that has deeply learned and internalised your data.</p>
<p>The trade-offs in 2025 are clearer than ever. Fine-tuning requires an upfront investment in data preparation and training costs, but it leads to faster inference, no need for context injection, and a more consistent personality. RAG systems are cheaper to set up and easier to update, but they need vector databases and can have trouble matching nuanced styles. Prompt engineering is free and immediate, but it limits how much customisation you can achieve.</p>
<p>As of September 2025, OpenAI supports supervised fine-tuning for three new models: GPT-4.1, GPT-4.1-mini, and GPT-4.1-nano. Each model has different capabilities and costs. GPT-4.1-nano is the most affordable option, ideal for simpler tasks. GPT-4.1-mini balances performance and cost, while GPT-4.1 offers the highest intelligence for complex, domain-specific applications.</p>
<p>Fine-tuning is best when you need a consistent voice and style, have specialised knowledge not well-covered by the base model, want to reduce delay by removing context injection, or need to ensure specific behaviours without complicated prompts. If your needs involve frequently changing information, simple factual lookups, or only occasional customisation, consider using RAG or prompt engineering instead.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we begin, make sure you have the following tools and accounts set up:</p>
<ol>
<li><p>Node.js v22+ and npm (check with <code>node --version</code>)</p>
</li>
<li><p>Basic JavaScript knowledge for the scripts</p>
</li>
<li><p>Familiarity with React and TypeScript for the web app</p>
</li>
<li><p>An OpenAI API key with billing enabled (get one at <a target="_blank" href="https://platform.openai.com/docs/overview">https://platform.openai.com/docs/overview</a>)</p>
</li>
<li><p>A code editor</p>
</li>
</ol>
<p>You'll also need some content to train your model on. This could be blog posts, documentation, transcripts, or any text that represents the knowledge and style you want to impart to your AI.</p>
<p>If you get stuck, you can check the GitHub repository for assistance or contact me (I'm happy to help fellow developers).</p>
<p><strong>Repository link:</strong> <a target="_blank" href="https://github.com/Sharvin26/ai-fine-tuning-project">https://github.com/Sharvin26/ai-fine-tuning-project</a></p>
<h2 id="heading-step-1-dataset-preparation">Step 1: Dataset Preparation</h2>
<p>The key to a successful fine-tuning project is having a well-prepared dataset. OpenAI needs training data in JSONL (JSON Lines) format, where each line is a complete JSON object representing a conversation. JSONL is a format where each line is a separate JSON object, which is great for handling large datasets efficiently. It allows for easy streaming and handling of data, making it ideal for machine learning tasks.</p>
<p>The JSONL structure that OpenAI requires for fine-tuning is as follows:</p>
<pre><code class="lang-json">{
   <span class="hljs-attr">"messages"</span>:[
      {
         <span class="hljs-attr">"role"</span>:<span class="hljs-string">"system"</span>,
         <span class="hljs-attr">"content"</span>:<span class="hljs-string">"You are a helpful assistant."</span>
      },
      {
         <span class="hljs-attr">"role"</span>:<span class="hljs-string">"user"</span>,
         <span class="hljs-attr">"content"</span>:<span class="hljs-string">"What is React?"</span>
      },
      {
         <span class="hljs-attr">"role"</span>:<span class="hljs-string">"assistant"</span>,
         <span class="hljs-attr">"content"</span>:<span class="hljs-string">"React is a JavaScript library..."</span>
      }
   ]
}
</code></pre>
<p>Each line represents a complete conversation. For fine-tuning to be effective, you need at least 10 examples, though 50-100 typically yields better results.</p>
<p>Let's build a Node.js scraper that extracts content from a website and converts it into the proper format.</p>
<p>First, let's set up our scripts folder structure:</p>
<pre><code class="lang-bash">mkdir ai-fine-tuning-project
<span class="hljs-built_in">cd</span> ai-fine-tuning-project
mkdir scripts
<span class="hljs-built_in">cd</span> scripts
npm init -y
npm install cheerio axios dotenv openai
touch scraper.js fine-tune.js .gitignore .env
</code></pre>
<p>Open the <code>ai-fine-tuning-project</code> in a code editor and copy the following values into a <code>.env</code> file in the scripts folder.</p>
<pre><code class="lang-bash">OPENAI_API_KEY=sk-...your-api-key-here...
OPENAI_ORG_ID=org-...your-org-id...
</code></pre>
<p>Update the ENV variables with a valid API Key and Org ID from OpenAI.</p>
<ol>
<li><p>Generate an API Key using this guide: <a target="_blank" href="https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key">Where do I find my OpenAI API Key?</a>. Here are the best practices to keep your API Key safe: <a target="_blank" href="https://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety">Best Practices for API Key Safety</a>.</p>
</li>
<li><p>You can find your OpenAI Org ID here: <a target="_blank" href="https://platform.openai.com/settings/organization/general">OpenAI Organization Settings</a>.</p>
</li>
</ol>
<p>Add the following code to the <code>.gitignore</code> file:</p>
<pre><code class="lang-plaintext"># Environment variables
.env
.env.local
.env.*.local

# Dependencies
node_modules/

# Logs
*.log
logs/

# Cache and temporary files
.cache/
temp/
tmp/

# OS files
.DS_Store
Thumbs.db

# IDE files
.vscode/
.idea/
*.swp
*.swo
</code></pre>
<p>Update the scraper script (<code>scraper.js</code>) with the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> cheerio = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cheerio"</span>);
<span class="hljs-keyword">const</span> axios = <span class="hljs-built_in">require</span>(<span class="hljs-string">"axios"</span>);
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);
<span class="hljs-keyword">const</span> OpenAI = <span class="hljs-built_in">require</span>(<span class="hljs-string">"openai"</span>);
<span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();

<span class="hljs-keyword">const</span> config = {
    <span class="hljs-attr">urls</span>: [
        {
            <span class="hljs-attr">url</span>: <span class="hljs-string">"https://www.mtechzilla.com/"</span>,
            <span class="hljs-attr">contentType</span>: <span class="hljs-string">"general"</span>,
        },
        {
            <span class="hljs-attr">url</span>: <span class="hljs-string">"https://www.mtechzilla.com/company/about-us"</span>,
            <span class="hljs-attr">contentType</span>: <span class="hljs-string">"about"</span>,
        },
        {
            <span class="hljs-attr">url</span>: <span class="hljs-string">"https://www.mtechzilla.com/services"</span>,
            <span class="hljs-attr">contentType</span>: <span class="hljs-string">"services"</span>,
        },
    ],
    <span class="hljs-attr">openai</span>: {
        <span class="hljs-attr">apiKey</span>: process.env.OPENAI_API_KEY,
        <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-5"</span>,
        <span class="hljs-attr">trainingExamples</span>: <span class="hljs-number">50</span>,
    },
    <span class="hljs-attr">outputFile</span>: <span class="hljs-string">"training_data.jsonl"</span>,
};

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AIScraper</span> </span>{
    <span class="hljs-keyword">constructor</span>(config) {
        <span class="hljs-built_in">this</span>.urls = config.urls;
        <span class="hljs-built_in">this</span>.openaiConfig = config.openai;
        <span class="hljs-built_in">this</span>.outputFile = config.outputFile;
        <span class="hljs-built_in">this</span>.scrapedContent = [];
        <span class="hljs-built_in">this</span>.trainingData = [];
        <span class="hljs-built_in">this</span>.openai = <span class="hljs-keyword">new</span> OpenAI({
            <span class="hljs-attr">apiKey</span>: <span class="hljs-built_in">this</span>.openaiConfig.apiKey,
        });
        <span class="hljs-built_in">this</span>.totalCost = <span class="hljs-number">0</span>;
    }

    <span class="hljs-keyword">async</span> fetchPage(url) {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(url, {
                <span class="hljs-attr">timeout</span>: <span class="hljs-number">30000</span>,
                <span class="hljs-attr">headers</span>: {
                    <span class="hljs-string">'User-Agent'</span>: <span class="hljs-string">'Mozilla/5.0 (compatible; AI-Training-Data-Scraper/1.0)'</span>
                }
            });
            <span class="hljs-keyword">return</span> response.data;
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`Failed to fetch <span class="hljs-subst">${url}</span>: <span class="hljs-subst">${error.message}</span>`</span>);
            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
        }
    }

    extractContent(html, urlConfig) {
        <span class="hljs-keyword">const</span> $ = cheerio.load(html);

        $(<span class="hljs-string">'script, style, nav, header, footer'</span>).remove();
        $(<span class="hljs-string">'[class*="cookie"], [class*="popup"], [class*="ad"]'</span>).remove();
        $(<span class="hljs-string">'button, .btn'</span>).remove();

        <span class="hljs-keyword">const</span> headings = [];
        $(<span class="hljs-string">'h1, h2, h3, h4'</span>).each(<span class="hljs-function">(<span class="hljs-params">_, elem</span>) =&gt;</span> {
            <span class="hljs-keyword">const</span> text = $(elem).text().trim();
            <span class="hljs-keyword">if</span> (text.length &gt; <span class="hljs-number">3</span> &amp;&amp; text.length &lt; <span class="hljs-number">200</span>) {
                headings.push(text);
            }
        });

        <span class="hljs-keyword">const</span> paragraphs = [];
        $(<span class="hljs-string">'p'</span>).each(<span class="hljs-function">(<span class="hljs-params">_, elem</span>) =&gt;</span> {
            <span class="hljs-keyword">const</span> text = $(elem).text().trim();
            <span class="hljs-keyword">if</span> (text.length &gt; <span class="hljs-number">20</span>) {
                paragraphs.push(text);
            }
        });

        <span class="hljs-keyword">const</span> listItems = [];
        $(<span class="hljs-string">'ul li, ol li'</span>).each(<span class="hljs-function">(<span class="hljs-params">_, elem</span>) =&gt;</span> {
            <span class="hljs-keyword">const</span> text = $(elem).text().trim();
            <span class="hljs-keyword">if</span> (text.length &gt; <span class="hljs-number">5</span> &amp;&amp; text.length &lt; <span class="hljs-number">200</span>) {
                listItems.push(text);
            }
        });

        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">url</span>: urlConfig.url,
            <span class="hljs-attr">contentType</span>: urlConfig.contentType,
            <span class="hljs-attr">title</span>: $(<span class="hljs-string">'title'</span>).text().trim(),
            <span class="hljs-attr">metaDescription</span>: $(<span class="hljs-string">'meta[name="description"]'</span>).attr(<span class="hljs-string">'content'</span>) || <span class="hljs-string">''</span>,
            <span class="hljs-attr">headings</span>: headings.slice(<span class="hljs-number">0</span>, <span class="hljs-number">10</span>),
            <span class="hljs-attr">paragraphs</span>: paragraphs.slice(<span class="hljs-number">0</span>, <span class="hljs-number">15</span>),
            <span class="hljs-attr">listItems</span>: listItems.slice(<span class="hljs-number">0</span>, <span class="hljs-number">20</span>)
        };
    }

    formatContentForPrompt(content) {
        <span class="hljs-keyword">let</span> formattedContent = <span class="hljs-string">`URL: <span class="hljs-subst">${content.url}</span>\n`</span>;
        formattedContent += <span class="hljs-string">`Content Type: <span class="hljs-subst">${content.contentType}</span>\n`</span>;
        formattedContent += <span class="hljs-string">`Title: <span class="hljs-subst">${content.title}</span>\n\n`</span>;

        <span class="hljs-keyword">if</span> (content.metaDescription) {
            formattedContent += <span class="hljs-string">`Description: <span class="hljs-subst">${content.metaDescription}</span>\n\n`</span>;
        }

        <span class="hljs-keyword">if</span> (content.headings.length &gt; <span class="hljs-number">0</span>) {
            formattedContent += <span class="hljs-string">`Headings:\n<span class="hljs-subst">${content.headings.map(h =&gt; <span class="hljs-string">`- <span class="hljs-subst">${h}</span>`</span>).join(<span class="hljs-string">'\n'</span>)}</span>\n\n`</span>;
        }

        <span class="hljs-keyword">if</span> (content.paragraphs.length &gt; <span class="hljs-number">0</span>) {
            formattedContent += <span class="hljs-string">`Content:\n<span class="hljs-subst">${content.paragraphs.join(<span class="hljs-string">'\n\n'</span>)}</span>\n\n`</span>;
        }

        <span class="hljs-keyword">if</span> (content.listItems.length &gt; <span class="hljs-number">0</span>) {
            formattedContent += <span class="hljs-string">`Features/Services:\n<span class="hljs-subst">${content.listItems.map(item =&gt; <span class="hljs-string">`- <span class="hljs-subst">${item}</span>`</span>).join(<span class="hljs-string">'\n'</span>)}</span>\n\n`</span>;
        }

        <span class="hljs-keyword">return</span> formattedContent;
    }

    <span class="hljs-keyword">async</span> generateTrainingDataWithAI() {
        <span class="hljs-keyword">const</span> allContent = <span class="hljs-built_in">this</span>.scrapedContent.map(<span class="hljs-function"><span class="hljs-params">content</span> =&gt;</span> 
            <span class="hljs-built_in">this</span>.formatContentForPrompt(content)
        ).join(<span class="hljs-string">'\n'</span> + <span class="hljs-string">'='</span>.repeat(<span class="hljs-number">50</span>) + <span class="hljs-string">'\n'</span>);

        <span class="hljs-keyword">const</span> prompt = <span class="hljs-string">`Based on the website content below, generate <span class="hljs-subst">${<span class="hljs-built_in">this</span>.openaiConfig.trainingExamples}</span> diverse, natural Q&amp;A pairs for training a customer service chatbot.

Website Content:
<span class="hljs-subst">${allContent}</span>

Create varied questions a real customer might ask, including:
- Company/business information
- Services or products offered  
- Contact and support questions
- General greetings and conversational questions
- FAQ-style questions

Make questions natural and human-like. Generate accurate answers based ONLY on the provided website content. Keep answers concise but informative.

Return a JSON object with a "training_data" array containing the Q&amp;A pairs.`</span>;

        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.openai.chat.completions.create({
                <span class="hljs-attr">model</span>: <span class="hljs-built_in">this</span>.openaiConfig.model,
                <span class="hljs-attr">messages</span>: [
                    {
                        <span class="hljs-attr">role</span>: <span class="hljs-string">"system"</span>,
                        <span class="hljs-attr">content</span>: <span class="hljs-string">"You are an expert at creating training data for AI chatbots. Always return valid JSON. Output your final JSON response directly without any reasoning or explanation."</span>
                    },
                    {
                        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
                        <span class="hljs-attr">content</span>: prompt,
                    },
                ],
                <span class="hljs-attr">response_format</span>: { 
                    <span class="hljs-attr">type</span>: <span class="hljs-string">"json_schema"</span>,
                    <span class="hljs-attr">json_schema</span>: {
                        <span class="hljs-attr">name</span>: <span class="hljs-string">"training_data_generation"</span>,
                        <span class="hljs-attr">schema</span>: {
                            <span class="hljs-attr">type</span>: <span class="hljs-string">"object"</span>,
                            <span class="hljs-attr">properties</span>: {
                                <span class="hljs-attr">training_data</span>: {
                                    <span class="hljs-attr">type</span>: <span class="hljs-string">"array"</span>,
                                    <span class="hljs-attr">items</span>: {
                                        <span class="hljs-attr">type</span>: <span class="hljs-string">"object"</span>,
                                        <span class="hljs-attr">properties</span>: {
                                            <span class="hljs-attr">question</span>: {
                                                <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
                                                <span class="hljs-attr">description</span>: <span class="hljs-string">"A natural question a customer might ask"</span>
                                            },
                                            <span class="hljs-attr">answer</span>: {
                                                <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>, 
                                                <span class="hljs-attr">description</span>: <span class="hljs-string">"An accurate answer based on the website content"</span>
                                            }
                                        },
                                        <span class="hljs-attr">required</span>: [<span class="hljs-string">"question"</span>, <span class="hljs-string">"answer"</span>]
                                    }
                                }
                            },
                            <span class="hljs-attr">required</span>: [<span class="hljs-string">"training_data"</span>]
                        }
                    }
                }
            });

            <span class="hljs-keyword">const</span> generatedContent = response.choices[<span class="hljs-number">0</span>].message.content?.trim();

            <span class="hljs-keyword">const</span> actualInputTokens = response.usage.prompt_tokens;
            <span class="hljs-keyword">const</span> actualOutputTokens = response.usage.completion_tokens;
            <span class="hljs-keyword">const</span> actualCost = (actualInputTokens * <span class="hljs-number">1.25</span> / <span class="hljs-number">1000000</span>) + (actualOutputTokens * <span class="hljs-number">10</span> / <span class="hljs-number">1000000</span>);
            <span class="hljs-built_in">this</span>.totalCost += actualCost;

            <span class="hljs-keyword">if</span> (!generatedContent) {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"No content generated in response"</span>);
            }

            <span class="hljs-keyword">const</span> structuredData = <span class="hljs-built_in">JSON</span>.parse(generatedContent);
            <span class="hljs-keyword">const</span> validTrainingData = [];

            <span class="hljs-keyword">if</span> (structuredData.training_data &amp;&amp; <span class="hljs-built_in">Array</span>.isArray(structuredData.training_data)) {
                structuredData.training_data.forEach(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> {
                    <span class="hljs-keyword">if</span> (item.question &amp;&amp; item.answer) {
                        validTrainingData.push({
                            <span class="hljs-attr">messages</span>: [
                                {
                                    <span class="hljs-attr">role</span>: <span class="hljs-string">"system"</span>,
                                    <span class="hljs-attr">content</span>: <span class="hljs-string">"You are a helpful assistant. Answer questions accurately based on the website content."</span>
                                },
                                {
                                    <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>, 
                                    <span class="hljs-attr">content</span>: item.question
                                },
                                {
                                    <span class="hljs-attr">role</span>: <span class="hljs-string">"assistant"</span>,
                                    <span class="hljs-attr">content</span>: item.answer
                                }
                            ]
                        });
                    }
                });
            }

            <span class="hljs-built_in">this</span>.trainingData = validTrainingData;
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Generated <span class="hljs-subst">${validTrainingData.length}</span> training examples`</span>);

        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`OpenAI API error: <span class="hljs-subst">${error.message}</span>`</span>);
            <span class="hljs-keyword">throw</span> error;
        }
    }

    <span class="hljs-keyword">async</span> scrape() {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Starting scraper for <span class="hljs-subst">${<span class="hljs-built_in">this</span>.urls.length}</span> URLs`</span>);

        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> urlConfig <span class="hljs-keyword">of</span> <span class="hljs-built_in">this</span>.urls) {
            <span class="hljs-keyword">const</span> html = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.fetchPage(urlConfig.url);

            <span class="hljs-keyword">if</span> (html) {
                <span class="hljs-keyword">const</span> content = <span class="hljs-built_in">this</span>.extractContent(html, urlConfig);
                <span class="hljs-built_in">this</span>.scrapedContent.push(content);
                <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Scraped: <span class="hljs-subst">${content.title || urlConfig.url}</span>`</span>);
            }

            <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> <span class="hljs-built_in">setTimeout</span>(resolve, <span class="hljs-number">1000</span>));
        }

        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.scrapedContent.length === <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"No content scraped successfully"</span>);
        }

        <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.generateTrainingDataWithAI();

        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Scraped <span class="hljs-subst">${<span class="hljs-built_in">this</span>.scrapedContent.length}</span> pages, generated <span class="hljs-subst">${<span class="hljs-built_in">this</span>.trainingData.length}</span> examples`</span>);
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Total cost: $<span class="hljs-subst">${<span class="hljs-built_in">this</span>.totalCost.toFixed(<span class="hljs-number">4</span>)}</span>`</span>);
    }

    saveToFile() {
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.trainingData.length === <span class="hljs-number">0</span>) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"No training data to save!"</span>);
            <span class="hljs-keyword">return</span>;
        }

        <span class="hljs-keyword">const</span> jsonl = <span class="hljs-built_in">this</span>.trainingData
            .map(<span class="hljs-function"><span class="hljs-params">example</span> =&gt;</span> <span class="hljs-built_in">JSON</span>.stringify(example))
            .join(<span class="hljs-string">'\n'</span>);

        fs.writeFileSync(<span class="hljs-built_in">this</span>.outputFile, jsonl);
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Saved <span class="hljs-subst">${<span class="hljs-built_in">this</span>.trainingData.length}</span> examples to <span class="hljs-subst">${<span class="hljs-built_in">this</span>.outputFile}</span>`</span>);
    }
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">if</span> (!config.openai.apiKey) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Please set your OpenAI API key in .env file"</span>);
            <span class="hljs-keyword">return</span>;
        }

        <span class="hljs-keyword">const</span> scraper = <span class="hljs-keyword">new</span> AIScraper(config);
        <span class="hljs-keyword">await</span> scraper.scrape();
        scraper.saveToFile();

        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Scraping complete!"</span>);

    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error:"</span>, error.message);
    }
}

main();
</code></pre>
<p>If you used a version of Node.js before 22, you might encounter issues when running the script. The recommended version is <code>v22.18.0</code>.</p>
<p>This code sets up an automated system for web scraping and creating AI-powered training data. It generates training datasets from website content. The script uses Cheerio to parse HTML from given URLs, extracting useful information like headings, paragraphs, and list items while ignoring unnecessary parts like scripts, navigation menus, and ads. After gathering the content, it uses OpenAI's API (configured to use GPT-4.1 with structured JSON output) to intelligently create natural question-and-answer pairs for fine-tuning purposes.</p>
<p>The generated Q&amp;A pairs are formatted into JSONL files according to OpenAI's fine-tuning format. Each entry includes a system message, a user question, and an assistant response. The scraper also has useful features like rate limiting between requests, error handling, and cost tracking based on token usage ($1.25 per million input tokens and $10 per million output tokens). This allows you to keep track of expenses while generating training data.</p>
<p>However, this is a basic script that can be improved based on your website's design, audience, and goals. While it extracts various content sections and creates diverse question-and-answer pairs, you'll need to manually check the output to ensure quality and correct formatting, as OpenAI will reject improperly formatted data. In production environments, this verification process can be automated by updating the script with additional validation logic and quality checks.</p>
<p>Now, let's create our <code>training_data.jsonl</code> file by running our scraper:</p>
<pre><code class="lang-bash">node scraper.js
</code></pre>
<p>You should see the following output:</p>
<pre><code class="lang-bash">Starting scraper <span class="hljs-keyword">for</span> 3 URLs
Scraped: MTechZilla: Custom Software and App Development Company
Scraped: About MTechZilla | Custom Software Development Agency
Scraped: Expert App &amp; Web Development Services | MTechZilla
Generated 50 training examples
Scraped 3 pages, generated 50 examples
Total cost: <span class="hljs-variable">$0</span>.0632
Saved 50 examples to training_data.jsonl
Scraping complete!
</code></pre>
<p><strong>Pro tip</strong>: Quality is more important than quantity. Review the generated <code>training_data.jsonl</code> file and refine any examples that don't accurately reflect the content or tone you want your AI to adopt.</p>
<h2 id="heading-step-2-fine-tuning-submission">Step 2: Fine-Tuning Submission</h2>
<p>With our dataset prepared, let's create a script to submit it to OpenAI for fine-tuning. We'll use the GPT-4.1 models and handle the entire process from upload to completion.</p>
<p>Update the fine-tuning script (<code>fine-tune.js</code>):</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> OpenAI = <span class="hljs-built_in">require</span>(<span class="hljs-string">"openai"</span>);
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);
<span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();

<span class="hljs-keyword">const</span> CONFIG = {
    <span class="hljs-comment">// Choose your base model for fine-tuning</span>
    <span class="hljs-attr">MODEL</span>: <span class="hljs-string">"gpt-4.1-nano-2025-04-14"</span>, <span class="hljs-comment">// Options: gpt-4.1-nano-2025-04-14, gpt-4.1-mini-2025-04-14, gpt-4.1-2025-04-14</span>

    <span class="hljs-comment">// Training file path</span>
    <span class="hljs-attr">TRAINING_FILE</span>: <span class="hljs-string">"training_data.jsonl"</span>,

    <span class="hljs-comment">// Polling interval for job status (in milliseconds)</span>
    <span class="hljs-attr">POLL_INTERVAL</span>: <span class="hljs-number">30000</span>, <span class="hljs-comment">// 30 seconds</span>
};

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FineTuningManager</span> </span>{
    <span class="hljs-keyword">constructor</span>() {
        <span class="hljs-keyword">if</span> (!process.env.OPENAI_API_KEY) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"OPENAI_API_KEY environment variable is required"</span>);
        }

        <span class="hljs-built_in">this</span>.openai = <span class="hljs-keyword">new</span> OpenAI({
            <span class="hljs-attr">apiKey</span>: process.env.OPENAI_API_KEY,
            <span class="hljs-attr">organization</span>: process.env.OPENAI_ORG_ID,
        });
    }

    <span class="hljs-comment">// Step 1: Validate training data format</span>
    validateTrainingData() {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"🔍 Validating training data format..."</span>);

        <span class="hljs-keyword">if</span> (!fs.existsSync(CONFIG.TRAINING_FILE)) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Training file not found: <span class="hljs-subst">${CONFIG.TRAINING_FILE}</span>`</span>);
        }

        <span class="hljs-keyword">const</span> content = fs.readFileSync(CONFIG.TRAINING_FILE, <span class="hljs-string">"utf-8"</span>);
        <span class="hljs-keyword">const</span> lines = content.split(<span class="hljs-string">"\n"</span>).filter(<span class="hljs-function"><span class="hljs-params">line</span> =&gt;</span> line.trim());

        <span class="hljs-keyword">if</span> (lines.length &lt; <span class="hljs-number">10</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Need at least 10 examples. Found: <span class="hljs-subst">${lines.length}</span>`</span>);
        }

        <span class="hljs-keyword">let</span> validExamples = <span class="hljs-number">0</span>;
        lines.forEach(<span class="hljs-function">(<span class="hljs-params">line, index</span>) =&gt;</span> {
            <span class="hljs-keyword">try</span> {
                <span class="hljs-keyword">const</span> data = <span class="hljs-built_in">JSON</span>.parse(line);

                <span class="hljs-comment">// Validate JSONL structure as per OpenAI documentation</span>
                <span class="hljs-keyword">if</span> (!data.messages || !<span class="hljs-built_in">Array</span>.isArray(data.messages) || data.messages.length &lt; <span class="hljs-number">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">`Invalid structure at line <span class="hljs-subst">${index + <span class="hljs-number">1</span>}</span>`</span>);
                }

                <span class="hljs-comment">// Check for required roles</span>
                <span class="hljs-keyword">const</span> hasUser = data.messages.some(<span class="hljs-function"><span class="hljs-params">m</span> =&gt;</span> m.role === <span class="hljs-string">'user'</span>);
                <span class="hljs-keyword">const</span> hasAssistant = data.messages.some(<span class="hljs-function"><span class="hljs-params">m</span> =&gt;</span> m.role === <span class="hljs-string">'assistant'</span>);

                <span class="hljs-keyword">if</span> (!hasUser || !hasAssistant) {
                    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Missing user or assistant message at line <span class="hljs-subst">${index + <span class="hljs-number">1</span>}</span>`</span>);
                }

                validExamples++;
            } <span class="hljs-keyword">catch</span> (e) {
                <span class="hljs-built_in">console</span>.warn(<span class="hljs-string">`⚠️ Skipping line <span class="hljs-subst">${index + <span class="hljs-number">1</span>}</span>: <span class="hljs-subst">${e.message}</span>`</span>);
            }
        });

        <span class="hljs-keyword">if</span> (validExamples &lt; <span class="hljs-number">10</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Need at least 10 valid examples. Found: <span class="hljs-subst">${validExamples}</span>`</span>);
        }

        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`✅ Validation passed: <span class="hljs-subst">${validExamples}</span> valid examples`</span>);
        <span class="hljs-keyword">return</span> validExamples;
    }

    <span class="hljs-comment">// Step 2: Upload training file to OpenAI</span>
    <span class="hljs-keyword">async</span> uploadTrainingFile() {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"📤 Uploading training file..."</span>);

        <span class="hljs-keyword">const</span> file = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.openai.files.create({
            <span class="hljs-attr">file</span>: fs.createReadStream(CONFIG.TRAINING_FILE),
            <span class="hljs-attr">purpose</span>: <span class="hljs-string">"fine-tune"</span>,
        });

        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`✅ File uploaded: <span class="hljs-subst">${file.id}</span>`</span>);
        <span class="hljs-keyword">return</span> file.id;
    }

    <span class="hljs-comment">// Step 3: Create fine-tuning job</span>
    <span class="hljs-keyword">async</span> createFineTuningJob(fileId) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`🚀 Creating fine-tuning job with model: <span class="hljs-subst">${CONFIG.MODEL}</span>`</span>);

        <span class="hljs-keyword">const</span> job = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.openai.fineTuning.jobs.create({
            <span class="hljs-attr">training_file</span>: fileId,
            <span class="hljs-attr">model</span>: CONFIG.MODEL,
            <span class="hljs-attr">method</span>: {
                <span class="hljs-attr">type</span>: <span class="hljs-string">"supervised"</span>
            }
        });

        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`✅ Fine-tuning job created: <span class="hljs-subst">${job.id}</span>`</span>);
        <span class="hljs-keyword">return</span> job.id;
    }

    <span class="hljs-comment">// Step 4: Monitor job until completion</span>
    <span class="hljs-keyword">async</span> monitorJob(jobId) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"⏳ Monitoring fine-tuning job..."</span>);
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"This typically takes 10-30 minutes...\n"</span>);

        <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
            <span class="hljs-keyword">const</span> job = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.openai.fineTuning.jobs.retrieve(jobId);

            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Status: <span class="hljs-subst">${job.status}</span>`</span>);

            <span class="hljs-keyword">if</span> (job.status === <span class="hljs-string">"succeeded"</span>) {
                <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"\n🎉 Fine-tuning completed successfully!"</span>);
                <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`🎆 Your fine-tuned model ID: <span class="hljs-subst">${job.fine_tuned_model}</span>`</span>);
                <span class="hljs-keyword">return</span> job.fine_tuned_model;
            } 

            <span class="hljs-keyword">if</span> (job.status === <span class="hljs-string">"failed"</span>) {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Fine-tuning failed: <span class="hljs-subst">${job.error?.message || <span class="hljs-string">'Unknown error'</span>}</span>`</span>);
            }

            <span class="hljs-keyword">if</span> (job.status === <span class="hljs-string">"cancelled"</span>) {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Fine-tuning was cancelled"</span>);
            }

            <span class="hljs-comment">// Wait before checking again</span>
            <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> <span class="hljs-built_in">setTimeout</span>(resolve, CONFIG.POLL_INTERVAL));
        }
    }

    <span class="hljs-comment">// Complete supervised fine-tuning workflow</span>
    <span class="hljs-keyword">async</span> runFineTuning() {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"🤖 Starting OpenAI Supervised Fine-Tuning\n"</span>);
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`📋 Using model: <span class="hljs-subst">${CONFIG.MODEL}</span>`</span>);
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`📄 Training file: <span class="hljs-subst">${CONFIG.TRAINING_FILE}</span>\n`</span>);

            <span class="hljs-comment">// Step 1: Validate data</span>
            <span class="hljs-keyword">const</span> validExamples = <span class="hljs-built_in">this</span>.validateTrainingData();

            <span class="hljs-comment">// Step 2: Upload file</span>
            <span class="hljs-keyword">const</span> fileId = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.uploadTrainingFile();

            <span class="hljs-comment">// Step 3: Create job</span>
            <span class="hljs-keyword">const</span> jobId = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.createFineTuningJob(fileId);

            <span class="hljs-comment">// Step 4: Monitor completion</span>
            <span class="hljs-keyword">const</span> modelId = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.monitorJob(jobId);

            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"\n"</span> + <span class="hljs-string">"="</span>.repeat(<span class="hljs-number">60</span>));
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"SUCCESS! Your fine-tuned model is ready!"</span>);
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"="</span>.repeat(<span class="hljs-number">60</span>));
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`\n Model ID: <span class="hljs-subst">${modelId}</span>`</span>);
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Trained on <span class="hljs-subst">${validExamples}</span> examples`</span>);
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"\n Next steps:"</span>);
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"1. Copy the Model ID above"</span>);
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"2. Use it in your application to access your custom model"</span>);

            <span class="hljs-keyword">return</span> modelId;

        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`\n❌ Fine-tuning failed: <span class="hljs-subst">${error.message}</span>`</span>);

            <span class="hljs-keyword">if</span> (error.message.includes(<span class="hljs-string">"not found"</span>)) {
                <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"💡 Tip: Make sure training_data.jsonl exists in the current directory"</span>);
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (error.message.includes(<span class="hljs-string">"API_KEY"</span>)) {
                <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"💡 Tip: Set OPENAI_API_KEY in your .env file"</span>);
            }

            <span class="hljs-keyword">throw</span> error;
        }
    }
}

<span class="hljs-comment">// Main execution</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> manager = <span class="hljs-keyword">new</span> FineTuningManager();
    <span class="hljs-keyword">await</span> manager.runFineTuning();
}

<span class="hljs-keyword">if</span> (<span class="hljs-built_in">require</span>.main === <span class="hljs-built_in">module</span>) {
    main().catch(<span class="hljs-built_in">console</span>.error);
}

<span class="hljs-built_in">module</span>.exports = FineTuningManager;
</code></pre>
<p>This script manages the entire fine-tuning process once your training data is ready from the scraper. It works as an automated manager, taking your JSONL training file and turning it into a custom OpenAI model designed for your specific needs. The process begins with thorough validation, ensuring your training file exists, has at least 10 valid examples, and follows OpenAI's required format with correct message roles (user and assistant). This validation step is important because OpenAI will reject data that isn't formatted correctly, so identifying issues early saves you time and API costs.</p>
<p>This script provides a complete fine-tuning workflow with the new GPT-4.1 models. You can choose from nano (cheapest), mini (balanced), or full (most capable) models, depending on your needs and budget. Once validation is successful, the script uploads your training file to OpenAI's servers and starts a fine-tuning job using your selected base model. The script uses supervised fine-tuning, which means your model learns directly from the question-answer pairs you provided, adjusting its responses to fit your website's information and tone.</p>
<p>The easiest part is the monitoring phase, where the script automatically checks the fine-tuning job status every 30 seconds until it's done. Fine-tuning usually takes 10-30 minutes, depending on your dataset size and the base model you chose. During the process, you'll get clear status updates in the console. Once it's finished, the script gives you your custom model ID, which you can use right away in your applications. It also provides helpful error messages and tips if something goes wrong, like reminding you to check your API key or verify that your training file exists.</p>
<p>Now let's submit our <code>training_data.jsonl</code> file for fine-tuning with the following command:</p>
<pre><code class="lang-bash">node fine-tune.js
</code></pre>
<p>You should see the following output:</p>
<pre><code class="lang-bash">🎉 Fine-tuning completed successfully!
🎆 Your fine-tuned model ID: ft:gpt-4.1-nano-2025-04-14:...

============================================================
SUCCESS! Your fine-tuned model is ready!
============================================================

 Model ID: ft:ft:gpt-4.1-nano-2025-04-14:...
Trained on 50 examples

 Next steps:
1. Copy the Model ID above
2. Use it <span class="hljs-keyword">in</span> your application to access your custom model
</code></pre>
<p><strong>Pro tip</strong>: Start with the nano model to test your dataset and workflow. It's the most cost-effective option and often enough for domain-specific knowledge. You can always train with a larger model later by updating configuration in <code>fine-tune.js</code>.</p>
<h2 id="heading-step-3-nextjs-application-setup">Step 3: Next.js Application Setup</h2>
<p>Now that our model is trained, let's build a modern chat application. We'll set up a separate web folder with a Next.js app using TypeScript and shadcn/ui for components.</p>
<p>First, navigate back to the project root:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ..
</code></pre>
<p>Then create the web application:</p>
<pre><code class="lang-bash">npx create-next-app@latest web
</code></pre>
<p>Choose the following options during the setup:</p>
<pre><code class="lang-bash">✔ Would you like to use TypeScript? › Yes
✔ Which linter would you like to use? › ESLint
✔ Would you like to use Tailwind CSS? › Yes
✔ Would you like your code inside a `src/` directory? › Yes
✔ Would you like to use App Router? (recommended) › Yes
✔ Would you like to use Turbopack? (recommended) › No
✔ Would you like to customize the import <span class="hljs-built_in">alias</span> (`@/*` by default)? › No
</code></pre>
<p>Navigate to the web directory:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> web
</code></pre>
<p>Install the required packages using the following command:</p>
<pre><code class="lang-bash">npm install ai @ai-sdk/openai @ai-sdk/react openai lucide-react
</code></pre>
<p>Now let's set up shadcn/ui for beautiful components:</p>
<pre><code class="lang-bash">npx shadcn@latest init
</code></pre>
<p>Choose the following option during the setup:</p>
<pre><code class="lang-bash">✔ Which color would you like to use as the base color? › Slate
</code></pre>
<p>And add the following shadcn components:</p>
<pre><code class="lang-bash">npx shadcn@latest add button
npx shadcn@latest add card
npx shadcn@latest add scroll-area
npx shadcn@latest add avatar
</code></pre>
<p>Create the <code>.env.local</code> file using the following command:</p>
<pre><code class="lang-json">touch .env.local
</code></pre>
<p>Add your environment variables in <code>web/.env.local</code>:</p>
<pre><code class="lang-bash">OPENAI_API_KEY=sk-...your-api-key...
OPENAI_ORG_ID=org-...your-org-id...
FINE_TUNED_MODEL=ft:gpt-4.1-nano-2025-04-14:... <span class="hljs-comment"># Your model ID from fine-tuning</span>
</code></pre>
<p>In the <code>src</code> directory, create a new folder named <code>types</code>. Inside this folder, create a file called <code>chat.ts</code> and copy and paste the following code:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// web/src/types/chat.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Message {
    id: <span class="hljs-built_in">string</span>;
    role: <span class="hljs-string">"user"</span> | <span class="hljs-string">"assistant"</span> | <span class="hljs-string">"system"</span>;
    content: <span class="hljs-built_in">string</span>;
    createdAt?: <span class="hljs-built_in">Date</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> ChatRequest {
    messages: Message[];
    model?: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> ChatResponse {
    message: Message;
    usage?: {
        prompt_tokens: <span class="hljs-built_in">number</span>;
        completion_tokens: <span class="hljs-built_in">number</span>;
        total_tokens: <span class="hljs-built_in">number</span>;
    };
}
</code></pre>
<p>This TypeScript code defines the data structures (interfaces) for a chat application, setting a standard for how messages and API interactions should be formatted in your app. The <code>Message</code> interface specifies what each chat message must include: a unique ID, a role indicating if it's from the user, assistant, or system, the message content, and an optional timestamp. The <code>ChatRequest</code> interface organizes the data you send to your fine-tuned model, including an array of messages (the conversation history) and an optional model parameter to specify which fine-tuned model to use.</p>
<p>Finally, the <code>ChatResponse</code> interface defines what you'll receive from the API: the assistant's reply message and optional usage statistics that show how many tokens were used for prompts and completions. This helps you track costs. By defining these interfaces, TypeScript ensures type safety throughout your application, catching errors during development and providing autocomplete suggestions in your code editor. This makes your chat application more robust and easier to maintain.</p>
<p>Update the <code>app/layout.tsx</code> with meta information and chat layout:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// web/app/layout.tsx</span>
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { Metadata } <span class="hljs-keyword">from</span> <span class="hljs-string">"next"</span>;
<span class="hljs-keyword">import</span> { Inter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/font/google"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./globals.css"</span>;

<span class="hljs-keyword">const</span> inter = Inter({ subsets: [<span class="hljs-string">"latin"</span>] });

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata: Metadata = {
    title: <span class="hljs-string">"AI Chat - Powered by Custom Fine-Tuned Model"</span>,
    description: <span class="hljs-string">"Chat with an AI trained on custom content"</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">RootLayout</span>(<span class="hljs-params">{
    children,
}: {
    children: React.ReactNode;
}</span>) </span>{
    <span class="hljs-keyword">return</span> (
        &lt;html lang=<span class="hljs-string">"en"</span> className=<span class="hljs-string">"h-full"</span>&gt;
            &lt;body
                className={<span class="hljs-string">`<span class="hljs-subst">${inter.className}</span> h-full bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-950 dark:to-slate-900`</span>}
                suppressHydrationWarning={<span class="hljs-literal">true</span>}
            &gt;
                {children}
            &lt;/body&gt;
        &lt;/html&gt;
    );
}
</code></pre>
<p>This code sets up the root layout for a Next.js application, acting as a wrapper around every page in your chat app. It starts by importing the Inter font from Google Fonts and configures it to use Latin characters, giving your application a clean, modern appearance.</p>
<p>The <code>metadata</code> object sets the page title and description that appear in browser tabs and search engine results, which is important for SEO and user experience. The <code>RootLayout</code> component brings everything together: it wraps all your app's pages (using the <code>children</code> prop) in a consistent HTML structure with full-height styling (<code>h-full</code>) and a pleasant gradient background. This background changes from light slate tones in light mode to dark slate in dark mode, automatically matching the user's system settings. The <code>suppressHydrationWarning</code> attribute addresses a common Next.js issue where server-rendered HTML might slightly differ from client-rendered HTML (often due to things like timestamps or theme detection), preventing console warnings.</p>
<p>This layout ensures that every page in your chat application shares the same basic styling, typography, and metadata, so you don't need to repeat the code on each page. It gives us a solid foundation with TypeScript for type safety, shadcn/ui for standard components, effective management of environment variables, and a clean project structure that is easy to maintain and expand.</p>
<h2 id="heading-step-4-building-the-chat-interface">Step 4: Building the Chat Interface</h2>
<p>Let's build a beautiful, responsive chat interface using shadcn components and the Vercel AI SDK's powerful streaming features.</p>
<p>First, create the main chat component in <code>src/components/chat.tsx</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// web/src/components/chat.tsx</span>
<span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> { useChat } <span class="hljs-keyword">from</span> <span class="hljs-string">"@ai-sdk/react"</span>;
<span class="hljs-keyword">import</span> { useRef, useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Send, Bot, User, Loader2, AlertCircle } <span class="hljs-keyword">from</span> <span class="hljs-string">"lucide-react"</span>;
<span class="hljs-keyword">import</span> { Button } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/ui/button"</span>;
<span class="hljs-keyword">import</span> {
    Card,
    CardContent,
    CardHeader,
    CardTitle,
    CardDescription,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/ui/card"</span>;
<span class="hljs-keyword">import</span> { ScrollArea } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/ui/scroll-area"</span>;
<span class="hljs-keyword">import</span> { Avatar, AvatarFallback } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/ui/avatar"</span>;
<span class="hljs-keyword">import</span> { cn } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/lib/utils"</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">Chat</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> scrollAreaRef = useRef&lt;HTMLDivElement&gt;(<span class="hljs-literal">null</span>);
    <span class="hljs-keyword">const</span> inputRef = useRef&lt;HTMLInputElement&gt;(<span class="hljs-literal">null</span>);
    <span class="hljs-keyword">const</span> [input, setInput] = useState(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">const</span> {
        messages,
        sendMessage,
        status,
        error,
        regenerate,
        stop,
        setMessages,
    } = useChat({
        onError: <span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Chat error:"</span>, error);
        },
        onFinish: <span class="hljs-function">() =&gt;</span> {
            inputRef.current?.focus();
        },
    });

    <span class="hljs-keyword">const</span> isLoading = status === <span class="hljs-string">"streaming"</span> || status === <span class="hljs-string">"submitted"</span>;

    <span class="hljs-comment">// Add welcome message on mount</span>
    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (messages.length === <span class="hljs-number">0</span>) {
            setMessages(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> [
                ...prev,
                {
                    id: <span class="hljs-string">"welcome"</span>,
                    role: <span class="hljs-string">"assistant"</span> <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>,
                    parts: [
                        {
                            <span class="hljs-keyword">type</span>: <span class="hljs-string">"text"</span> <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>,
                            text: <span class="hljs-string">"Hello! I'm your custom AI assistant, trained on specific content. How can I help you today?"</span>,
                        },
                    ],
                },
            ]);
        }
    }, [messages.length, setMessages]);

    <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e: React.FormEvent</span>) =&gt;</span> {
        e.preventDefault();
        <span class="hljs-keyword">if</span> (!input.trim() || isLoading) <span class="hljs-keyword">return</span>;

        sendMessage({
            role: <span class="hljs-string">"user"</span>,
            parts: [{ <span class="hljs-keyword">type</span>: <span class="hljs-string">"text"</span>, text: input }],
        });
        setInput(<span class="hljs-string">""</span>);
    };

    <span class="hljs-keyword">const</span> handleInputChange = <span class="hljs-function">(<span class="hljs-params">e: React.ChangeEvent&lt;HTMLInputElement&gt;</span>) =&gt;</span> {
        setInput(e.target.value);
    };

    <span class="hljs-comment">// Auto-scroll to bottom when new messages arrive</span>
    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (scrollAreaRef.current) {
            <span class="hljs-keyword">const</span> scrollContainer = scrollAreaRef.current.querySelector(
                <span class="hljs-string">"[data-radix-scroll-area-viewport]"</span>
            );
            <span class="hljs-keyword">if</span> (scrollContainer) {
                scrollContainer.scrollTop = scrollContainer.scrollHeight;
            }
        }
    }, [messages]);


    <span class="hljs-keyword">return</span> (
        &lt;div className=<span class="hljs-string">"flex h-screen max-w-5xl mx-auto p-4"</span>&gt;
            &lt;Card className=<span class="hljs-string">"flex-1 flex flex-col shadow-xl overflow-hidden"</span>&gt;
                {<span class="hljs-comment">/* Header */</span>}
                &lt;CardHeader className=<span class="hljs-string">"border-b flex-shrink-0"</span>&gt;
                    &lt;div className=<span class="hljs-string">"flex items-center space-x-4"</span>&gt;
                        &lt;div className=<span class="hljs-string">"relative"</span>&gt;
                            &lt;Avatar className=<span class="hljs-string">"h-10 w-10"</span>&gt;
                                &lt;AvatarFallback className=<span class="hljs-string">"bg-primary text-primary-foreground"</span>&gt;
                                    &lt;Bot className=<span class="hljs-string">"h-6 w-6"</span> /&gt;
                                &lt;/AvatarFallback&gt;
                            &lt;/Avatar&gt;
                            &lt;div className=<span class="hljs-string">"absolute -bottom-0.5 -right-0.5 w-3 h-3 bg-green-500 rounded-full border-2 border-background animate-pulse"</span> /&gt;
                        &lt;/div&gt;
                        &lt;div className=<span class="hljs-string">"flex-1"</span>&gt;
                            &lt;CardTitle&gt;Custom AI Assistant&lt;/CardTitle&gt;
                            &lt;CardDescription&gt;
                                Powered by your fine-tuned model
                            &lt;/CardDescription&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/CardHeader&gt;

                {<span class="hljs-comment">/* Messages Area */</span>}
                &lt;ScrollArea ref={scrollAreaRef} className=<span class="hljs-string">"flex-1 min-h-0"</span>&gt;
                    &lt;div className=<span class="hljs-string">"p-4 space-y-4 pb-4"</span>&gt;
                        {messages.map(<span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> {
                            <span class="hljs-keyword">const</span> isUser = (message.role <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>) === <span class="hljs-string">"user"</span>;
                            <span class="hljs-keyword">return</span> (
                                &lt;div
                                    key={message.id}
                                    className={cn(
                                        <span class="hljs-string">"flex"</span>,
                                        isUser ? <span class="hljs-string">"justify-end"</span> : <span class="hljs-string">"justify-start"</span>
                                    )}
                                &gt;
                                    &lt;div
                                        className={cn(
                                            <span class="hljs-string">"flex items-start gap-3 max-w-[85%] min-w-0"</span>,
                                            isUser &amp;&amp; <span class="hljs-string">"flex-row-reverse"</span>
                                        )}
                                    &gt;
                                        {<span class="hljs-comment">/* Avatar */</span>}
                                        &lt;Avatar className=<span class="hljs-string">"h-8 w-8 shrink-0"</span>&gt;
                                            &lt;AvatarFallback
                                                className={cn(
                                                    isUser
                                                        ? <span class="hljs-string">"bg-primary text-primary-foreground"</span>
                                                        : <span class="hljs-string">"bg-muted"</span>
                                                )}
                                            &gt;
                                                {isUser ? (
                                                    &lt;User className=<span class="hljs-string">"h-4 w-4"</span> /&gt;
                                                ) : (
                                                    &lt;Bot className=<span class="hljs-string">"h-4 w-4"</span> /&gt;
                                                )}
                                            &lt;/AvatarFallback&gt;
                                        &lt;/Avatar&gt;

                                        {<span class="hljs-comment">/* Message Content */</span>}
                                        &lt;div className=<span class="hljs-string">"space-y-1 min-w-0 flex-1"</span>&gt;
                                            &lt;div
                                                className={cn(
                                                    <span class="hljs-string">"rounded-lg px-4 py-2.5 text-sm max-w-full"</span>,
                                                    isUser
                                                        ? <span class="hljs-string">"bg-primary text-primary-foreground"</span>
                                                        : <span class="hljs-string">"bg-muted"</span>
                                                )}
                                            &gt;
                                                &lt;div className=<span class="hljs-string">"whitespace-pre-wrap break-words leading-relaxed overflow-wrap-anywhere"</span>&gt;
                                                    {message.parts?.map(<span class="hljs-function">(<span class="hljs-params">part, index</span>) =&gt;</span> {
                                                        <span class="hljs-keyword">if</span> (part.type === <span class="hljs-string">"text"</span>) {
                                                            <span class="hljs-keyword">return</span> &lt;p key={index}&gt;{part.text}&lt;/p&gt;;
                                                        }
                                                        <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
                                                    })}
                                                &lt;/div&gt;
                                            &lt;/div&gt;
                                        &lt;/div&gt;
                                    &lt;/div&gt;
                                &lt;/div&gt;
                            );
                        })}

                        {<span class="hljs-comment">/* Loading Indicator */</span>}
                        {isLoading &amp;&amp; (
                            &lt;div className=<span class="hljs-string">"flex justify-start"</span>&gt;
                                &lt;div className=<span class="hljs-string">"flex items-center gap-3 max-w-[85%]"</span>&gt;
                                    &lt;Avatar className=<span class="hljs-string">"h-8 w-8"</span>&gt;
                                        &lt;AvatarFallback className=<span class="hljs-string">"bg-muted"</span>&gt;
                                            &lt;Bot className=<span class="hljs-string">"h-4 w-4"</span> /&gt;
                                        &lt;/AvatarFallback&gt;
                                    &lt;/Avatar&gt;
                                    &lt;div className=<span class="hljs-string">"bg-muted rounded-lg px-4 py-2.5"</span>&gt;
                                        &lt;div className=<span class="hljs-string">"flex items-center gap-2"</span>&gt;
                                            &lt;Loader2 className=<span class="hljs-string">"h-3 w-3 animate-spin"</span> /&gt;
                                            &lt;span className=<span class="hljs-string">"text-sm text-muted-foreground"</span>&gt;
                                                Thinking...
                                            &lt;/span&gt;
                                        &lt;/div&gt;
                                    &lt;/div&gt;
                                &lt;/div&gt;
                            &lt;/div&gt;
                        )}

                        {<span class="hljs-comment">/* Error Message */</span>}
                        {error &amp;&amp; (
                            &lt;div className=<span class="hljs-string">"flex justify-center px-4"</span>&gt;
                                &lt;div className=<span class="hljs-string">"bg-destructive/10 border border-destructive/20 rounded-lg p-3 max-w-md"</span>&gt;
                                    &lt;div className=<span class="hljs-string">"flex items-start gap-2"</span>&gt;
                                        &lt;AlertCircle className=<span class="hljs-string">"h-4 w-4 text-destructive mt-0.5"</span> /&gt;
                                        &lt;div className=<span class="hljs-string">"space-y-1"</span>&gt;
                                            &lt;p className=<span class="hljs-string">"text-sm text-destructive"</span>&gt;
                                                {error.message ||
                                                    <span class="hljs-string">"Something went wrong. Please try again."</span>}
                                            &lt;/p&gt;
                                            &lt;Button
                                                onClick={<span class="hljs-function">() =&gt;</span> regenerate()}
                                                variant=<span class="hljs-string">"ghost"</span>
                                                size=<span class="hljs-string">"sm"</span>
                                                className=<span class="hljs-string">"h-7 px-2 text-xs"</span>
                                            &gt;
                                                Retry last message
                                            &lt;/Button&gt;
                                        &lt;/div&gt;
                                    &lt;/div&gt;
                                &lt;/div&gt;
                            &lt;/div&gt;
                        )}
                    &lt;/div&gt;
                &lt;/ScrollArea&gt;

                {<span class="hljs-comment">/* Input Area */</span>}
                &lt;CardContent className=<span class="hljs-string">"border-t p-4 flex-shrink-0"</span>&gt;
                    &lt;form onSubmit={handleSubmit} className=<span class="hljs-string">"flex gap-2"</span>&gt;
                        &lt;input
                            ref={inputRef}
                            <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
                            value={input}
                            onChange={handleInputChange}
                            placeholder=<span class="hljs-string">"Type your message..."</span>
                            disabled={isLoading}
                            className={cn(
                                <span class="hljs-string">"flex-1 px-3 py-2 text-sm rounded-md border border-input bg-background"</span>,
                                <span class="hljs-string">"placeholder:text-muted-foreground"</span>,
                                <span class="hljs-string">"focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"</span>,
                                <span class="hljs-string">"disabled:cursor-not-allowed disabled:opacity-50"</span>
                            )}
                            autoFocus
                        /&gt;

                        {isLoading ? (
                            &lt;Button
                                <span class="hljs-keyword">type</span>=<span class="hljs-string">"button"</span>
                                onClick={stop}
                                variant=<span class="hljs-string">"destructive"</span>
                                size=<span class="hljs-string">"sm"</span>
                            &gt;
                                Stop
                            &lt;/Button&gt;
                        ) : (
                            &lt;Button
                                <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>
                                disabled={!input.trim()}
                                size=<span class="hljs-string">"sm"</span>
                            &gt;
                                &lt;Send className=<span class="hljs-string">"h-4 w-4"</span> /&gt;
                                &lt;span className=<span class="hljs-string">"ml-2 hidden sm:inline"</span>&gt;
                                    Send
                                &lt;/span&gt;
                            &lt;/Button&gt;
                        )}
                    &lt;/form&gt;

                    {<span class="hljs-comment">/* Character Counter */</span>}
                    {input.length &gt; <span class="hljs-number">0</span> &amp;&amp; (
                        &lt;div className=<span class="hljs-string">"mt-2 text-xs text-muted-foreground text-right"</span>&gt;
                            {input.length} / <span class="hljs-number">4000</span>
                        &lt;/div&gt;
                    )}
                &lt;/CardContent&gt;
            &lt;/Card&gt;
        &lt;/div&gt;
    );
}
</code></pre>
<p>This code creates the main chat interface component where users interact with your fine-tuned AI model. It primarily uses the <code>useChat</code> hook from Vercel's AI SDK, which manages all the complex messaging tasks, such as sending messages, receiving streaming responses, managing conversation state, and handling errors. The component sets up several React hooks: <code>useRef</code> for managing DOM elements like the scroll area and input field, <code>useState</code> for the input text, and <code>useEffect</code> for side effects like auto-scrolling and showing a welcome message when the chat first loads.</p>
<p>The UI is built using shadcn/ui components to create a polished, professional look with minimal effort. The layout has three main sections: a header showing the AI assistant's status (with a pulsing green dot to indicate it's online), a scrollable message area in the middle, and an input form at the bottom. Each message is displayed with an avatar (a user icon for human messages and a bot icon for AI responses) and styled differently based on who sent it. User messages appear on the right with a primary color background, while assistant messages appear on the left with a muted background. The component includes thoughtful UX details like automatic scrolling to the latest message, focus management that returns to the input field after sending, and a character counter showing how close you are to the 4000-character limit.</p>
<p>The component also manages different states smoothly: it shows a "Thinking..." animation with a spinning loader while the AI creates a response, displays error messages with a retry button if something goes wrong, and even lets users stop the response mid-stream if it takes too long. When loading, the send button changes into a "Stop" button, giving users full control over the conversation. Everything is wrapped in responsive styling that adjusts to different screen sizes, ensuring your chat interface looks great whether users are on desktop or mobile devices.</p>
<p>Now, update the main page to use the chat component:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// web/app/page.tsx</span>
<span class="hljs-keyword">import</span> Chat <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/chat"</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> (
        &lt;main className=<span class="hljs-string">"h-screen"</span>&gt;
            &lt;Chat /&gt;
        &lt;/main&gt;
    );
}
</code></pre>
<p>This chat interface uses shadcn/ui components to create a polished, professional look. It includes features like real-time message streaming, animated loading states, error handling with retry options, automatic scrolling to the latest messages, a responsive design for all devices, keyboard shortcuts, accessibility features, and a character counter to keep users informed.</p>
<h2 id="heading-step-5-api-route-integration">Step 5: API Route Integration</h2>
<p>Now let's create the backend API route that connects our chat interface to the fine-tuned OpenAI model with proper streaming support.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// web/app/api/chat/route.ts</span>
<span class="hljs-keyword">import</span> { openai } <span class="hljs-keyword">from</span> <span class="hljs-string">"@ai-sdk/openai"</span>;
<span class="hljs-keyword">import</span> { streamText, convertToModelMessages } <span class="hljs-keyword">from</span> <span class="hljs-string">"ai"</span>;
<span class="hljs-keyword">import</span> { NextRequest, NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/server"</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">POST</span>(<span class="hljs-params">req: NextRequest</span>) </span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Parse request body</span>
        <span class="hljs-keyword">const</span> body = <span class="hljs-keyword">await</span> req.json();
        <span class="hljs-keyword">const</span> { messages } = body;

        <span class="hljs-comment">// Validate messages</span>
        <span class="hljs-keyword">if</span> (!messages || !<span class="hljs-built_in">Array</span>.isArray(messages)) {
            <span class="hljs-keyword">return</span> NextResponse.json(
                { error: <span class="hljs-string">"Invalid request format"</span> },
                { status: <span class="hljs-number">400</span> }
            );
        }

        <span class="hljs-comment">// Convert UI messages to model messages using AI SDK utility</span>
        <span class="hljs-keyword">const</span> modelMessages = convertToModelMessages(messages);

        <span class="hljs-comment">// Check if we have any valid messages</span>
        <span class="hljs-keyword">if</span> (modelMessages.length === <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">return</span> NextResponse.json(
                { error: <span class="hljs-string">"No valid messages provided"</span> },
                { status: <span class="hljs-number">400</span> }
            );
        }

        <span class="hljs-comment">// Add system prompt to prevent hallucination and guide the model</span>
        <span class="hljs-keyword">const</span> systemPrompt = {
            role: <span class="hljs-string">"system"</span> <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>,
            content: <span class="hljs-string">`You are a helpful assistant answering questions about MTechZilla, a software development company. 

IMPORTANT INSTRUCTIONS:
- Only answer questions based on information you were specifically trained on about MTechZilla
- If you don't know something or weren't trained on specific information, say "I don't have that specific information in my training data"
- Never make up or guess information about MTechZilla
- Be accurate and only provide information you're confident about

Answer questions accurately based on your training data about MTechZilla's services, technologies, and approach.`</span>
        };

        <span class="hljs-comment">// Prepend system message if not already present</span>
        <span class="hljs-keyword">const</span> hasSystemMessage = modelMessages.some(<span class="hljs-function"><span class="hljs-params">msg</span> =&gt;</span> msg.role === <span class="hljs-string">'system'</span>);
        <span class="hljs-keyword">if</span> (!hasSystemMessage) {
            modelMessages.unshift(systemPrompt);
        }

        <span class="hljs-comment">// Load fine-tuned model ID from environment variable</span>
        <span class="hljs-keyword">const</span> fineTunedModelId = process.env.FINE_TUNED_MODEL;

        <span class="hljs-comment">// Ensure we have a valid model ID</span>
        <span class="hljs-keyword">if</span> (!fineTunedModelId) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"No fine-tuned model ID available"</span>);
        }

        <span class="hljs-comment">// Call OpenAI with streaming using the new AI SDK</span>
        <span class="hljs-keyword">const</span> result = streamText({
            model: openai(fineTunedModelId),
            messages: modelMessages,
            temperature: <span class="hljs-number">0.1</span>, <span class="hljs-comment">// Lower temperature for more deterministic, factual responses</span>
        });

        <span class="hljs-comment">// Log stream start</span>
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Stream started`</span>);

        <span class="hljs-comment">// Return UI message stream response for useChat compatibility</span>
        <span class="hljs-keyword">return</span> result.toUIMessageStreamResponse({
            headers: {
                <span class="hljs-string">"Cache-Control"</span>: <span class="hljs-string">"no-cache, no-transform"</span>,
                <span class="hljs-string">"X-Accel-Buffering"</span>: <span class="hljs-string">"no"</span>,
            },
        });
    } <span class="hljs-keyword">catch</span> (error: unknown) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Chat API Error:"</span>, error);

        <span class="hljs-comment">// Handle specific errors</span>
        <span class="hljs-keyword">if</span> (error &amp;&amp; <span class="hljs-keyword">typeof</span> error === <span class="hljs-string">"object"</span> &amp;&amp; <span class="hljs-string">"status"</span> <span class="hljs-keyword">in</span> error) {
            <span class="hljs-keyword">const</span> errorWithStatus = error <span class="hljs-keyword">as</span> { status: <span class="hljs-built_in">number</span> };

            <span class="hljs-keyword">if</span> (errorWithStatus.status === <span class="hljs-number">401</span>) {
                <span class="hljs-keyword">return</span> NextResponse.json(
                    {
                        error: <span class="hljs-string">"Authentication failed. Check API key configuration."</span>,
                    },
                    { status: <span class="hljs-number">401</span> }
                );
            }

            <span class="hljs-keyword">if</span> (errorWithStatus.status === <span class="hljs-number">404</span>) {
                <span class="hljs-keyword">return</span> NextResponse.json(
                    {
                        error: <span class="hljs-string">"Model not found. Check your fine-tuned model ID."</span>,
                    },
                    { status: <span class="hljs-number">404</span> }
                );
            }

            <span class="hljs-keyword">if</span> (errorWithStatus.status === <span class="hljs-number">429</span>) {
                <span class="hljs-keyword">return</span> NextResponse.json(
                    {
                        error: <span class="hljs-string">"OpenAI rate limit reached. Please try again later."</span>,
                    },
                    { status: <span class="hljs-number">429</span> }
                );
            }
        }

        <span class="hljs-comment">// Generic error</span>
        <span class="hljs-keyword">return</span> NextResponse.json(
            { error: <span class="hljs-string">"An error occurred. Please try again."</span> },
            { status: <span class="hljs-number">500</span> }
        );
    }
}
</code></pre>
<p>This code sets up the backend API endpoint that connects your chat interface to your fine-tuned OpenAI model. When a user sends a message, this Next.js API route receives the request, checks if the messages are correctly formatted, and converts them from the UI format to the structure that OpenAI's API needs using the AI SDK's <code>convertToModelMessages</code> tool. A key feature is the system prompt injection before sending messages to your model. The code automatically adds specific instructions, telling the AI to only respond based on its training data about MTechZilla (in this example) and to clearly say "I don't have that specific information" instead of making things up. This is crucial for preventing errors and ensuring the chatbot remains accurate and reliable.</p>
<p>The route loads your fine-tuned model ID from environment variables to keep sensitive settings secure. It uses Vercel's AI SDK to call OpenAI with streaming enabled, so responses appear word-by-word in real-time instead of waiting for the entire response. The temperature is set to 0.1, making the model more predictable and factual—perfect for a customer service chatbot where accuracy is more important than creativity. The <code>streamText</code> function handles all the streaming details, and the response is returned in a format that works directly with the <code>useChat</code> hook in your frontend component.</p>
<p>The code includes thorough error handling for common issues: authentication failures (invalid API keys), model not found errors (incorrect model ID), rate limiting (too many requests), and general server errors. Each error type returns a specific, helpful message to make debugging easier during development and to provide clear feedback to users if something goes wrong. The response headers include cache control directives to ensure fresh data and prevent buffering issues during streaming, guaranteeing a smooth, real-time chat experience for your users.</p>
<h2 id="heading-step-6-testing-your-application">Step 6: Testing Your Application</h2>
<p>With everything set up, let's test the complete application and ensure it works correctly.</p>
<p>First, make sure you've added your fine-tuned model ID to the environment file:</p>
<pre><code class="lang-bash">OPENAI_API_KEY=sk-...your-api-key...
OPENAI_ORG_ID=org-...your-org-id...
FINE_TUNED_MODEL=ft:gpt-4.1-nano-2025-04-14:... <span class="hljs-comment"># Copy from scripts/model_info.json</span>
</code></pre>
<p>Start the development server:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>Open <a target="_blank" href="http://localhost:3000">http://localhost:3000</a> in your browser, and you'll see the following UI:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757941475393/692f92ff-11bc-451d-a9fa-a288c87f7d78.png" alt="Screenshot of a chat window with &quot;Custom AI Assistant&quot; at the top. The AI greets the user, saying, &quot;Hello! I'm your custom AI assistant, trained on specific content. How can I help you today?&quot; A message input field and send button are at the bottom." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Test various scenarios:</p>
<ol>
<li><p><strong>Domain Knowledge Test</strong>: Ask questions related to your training data</p>
</li>
<li><p><strong>Conversation Flow</strong>: Have a multi-turn conversation</p>
</li>
<li><p><strong>Edge Cases</strong>: Try very long inputs, rapid messages, network interruptions</p>
</li>
<li><p><strong>Mobile Testing</strong>: Test on different screen sizes</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations! You've successfully fine-tuned a GPT-4.1 model and built a chat application ready for production, showing the power of custom AI. We've transformed raw website content into structured training data, used OpenAI's latest models for fine-tuning, and built a modern Next.js app with real-time streaming and a nice interface. The key to successful fine-tuning is knowing when it's the right choice - use it for a consistent brand voice, specialised domain knowledge, and reducing RAG complexity, but consider the RAG option for information that changes often. Our modular project structure keeps training scripts separate from the web app, making it easy to retrain models and add new features.</p>
<p>As you continue, remember that fine-tuning is a step-by-step process. Watch how users interact, gather feedback, and keep improving your model with new training examples. Avoid common mistakes like using too little data (aim for 50+ good examples), ignoring validation errors, and not setting up proper rate limits and error handling. In 2025, AI customisation is changing fast, with trends toward more efficient models, continuous learning, and hybrid methods that mix different techniques. What used to need a team of ML engineers can now be done by few developers with the right skills. You now have the tools and knowledge to create specialised AI applications that truly understand and serve your specific area.</p>
<p><em>For founders considering AI adoption, I've created a free guide:</em> <a target="_blank" href="https://www.notion.so/AI-or-No-AI-The-2025-Founder-s-Decision-Playbook-25ec9ed724ec80668a8fc42bb804515a"><em>AI or No AI? The 2025 Founder's Decision Playbook</em></a> <em>- a framework to help decide when AI truly adds value.</em></p>
<p><em>Feel free to connect with me on</em> <a target="_blank" href="https://www.linkedin.com/in/sharvinshah/"><em>LinkedIn</em></a> <em>and</em> <a target="_blank" href="https://twitter.com/sharvinshah26"><em>Twitter</em></a><em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Production Ready eCommerce Website with ReactJS, TailwindCSS, PlanetScale and Stripe ]]>
                </title>
                <description>
                    <![CDATA[ Hello, welcome to this tutorial. Today we're going to build a production-ready eCommerce website using ReactJS, TailwindCSS, PlanetScale, and Stripe. Before we begin, you should be familiar with the basics of React.js and Next.js to get the most out ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-ecommerce-website-using-next-js-and-planetscale/</link>
                <guid isPermaLink="false">66d460ef4a0edd9b48e83583</guid>
                
                    <category>
                        <![CDATA[ ecommerce ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ stripe ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tailwind ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sharvin Shah ]]>
                </dc:creator>
                <pubDate>Tue, 25 Oct 2022 16:30:14 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/10/Add-a-heading.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hello, welcome to this tutorial. Today we're going to build a production-ready eCommerce website using ReactJS, TailwindCSS, PlanetScale, and Stripe.</p>
<p>Before we begin, you should be familiar with the basics of React.js and Next.js to get the most out of this guide.</p>
<p>If you're not and need to brush up, I recommend you go through the <a target="_blank" href="https://reactjs.org/docs/getting-started.html">ReactJS</a> and <a target="_blank" href="https://nextjs.org/docs/getting-started">NextJS documentation</a>.</p>
<h2 id="heading-the-stack-we-will-use">The stack we will use:</h2>
<ol>
<li><p><a target="_blank" href="https://reactjs.org/docs/getting-started.html">ReactJS</a> is a JavaScript library for building user interfaces. It is declarative and component-based.</p>
</li>
<li><p><a target="_blank" href="https://nextjs.org/docs/getting-started">NextJS</a> is a React-based framework that lets us render data on the server side. It helps Google crawl the application which results in SEO benefits.</p>
</li>
<li><p><a target="_blank" href="https://planetscale.com/docs">PlanetScale</a> is a database as a service that is developed on Vitess, an open-source technology that powers YouTube and uses MySQL internally.</p>
</li>
<li><p><a target="_blank" href="https://tailwindcss.com/">TailwindCSS</a> is a utility-first CSS framework packed with classes that can be composed to build any design, directly in our markup.</p>
</li>
<li><p><a target="_blank" href="https://www.prisma.io/docs/">Prisma</a> is an ORM built for NodeJS and TypeScript which handles automated migrations, type-safety, and auto-completion.</p>
</li>
<li><p><a target="_blank" href="https://vercel.com/docs">Vercel</a> will host our application. It scales well, all without any configuration, and deployment is instant.</p>
</li>
<li><p><a target="_blank" href="https://stripe.com">Stripe</a> is a payment gateway, and we will use it to accept online payments on the website.</p>
</li>
</ol>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#how-to-configure-planetscale-prisma-nextjs-and-stripe-">How to Configure PlanetScale, Stripe, NextJS, Prisma and Other Libraries</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-mock-data-category-products-api-and-all-category-single-category-ui">How to Implement Mock Data, Category-Products API and All Category-Single Category UI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-single-product-ui-and-stripe-checkout">How to Implement Single Product UI and Stripe Checkout</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-deploy-the-website-to-production">How to Deploy the Website to Production</a></p>
</li>
</ol>
<p>I am going to divide this tutorial into four separate sections.</p>
<p>At the start of every section, you will find a Git commit that has the code developed in that section. Also, if you want to see the complete code, then it is available in this <a target="_blank" href="https://github.com/Sharvin26/Ecommerce-Website-ReactJS-TailwindCSS-PlanetScale-Stripe">repository</a>.</p>
<h2 id="heading-how-to-configure-planetscale-stripe-nextjs-tailwindcss-and-prisma">How to Configure PlanetScale, Stripe, NextJS, TailwindCSS, and Prisma.</h2>
<p>In this section, we'll implement the following functionality:</p>
<ol>
<li><p>Create a PlanetScale Account and Database.</p>
</li>
<li><p>Create a Stripe Account.</p>
</li>
<li><p>Configure NextJS, TailwindCSS, and Prisma.</p>
</li>
</ol>
<p>You can find the <strong>eCommerce</strong> website <strong>code</strong> implemented in this section at this <a target="_blank" href="https://github.com/Sharvin26/Ecommerce-Website-ReactJS-TailwindCSS-PlanetScale-Stripe/tree/afa389dc07f565a39eacac5e3801fcc4e8d9041f">commit</a>.</p>
<h3 id="heading-how-to-configure-planetscale">How to Configure PlanetScale:</h3>
<p>To create a PlanetScale account, visit this <a target="_blank" href="https://planetscale.com/">URL</a>. Click on Get started button at the top right corner.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-2.01.59-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>PlanetScale Landing Page</em></p>
<p>You can either create an account using GitHub or a traditional email-password. Once the account is created, then click on the "create" link.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-05-at-5.00.59-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>PlanetScale Dashboard Page</em></p>
<p>You'll receive the following modal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-05-at-5.08.12-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>PlanetScale New Database Modal</em></p>
<p>Fill in the details and click on the Create database button. Once the database is created you'll be redirected to the following page:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-2.06.05-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>PlanetScale Ecommerce Website Database Page</em></p>
<p>Click on connect and a modal will open. This modal will contain a Database URL and this password cannot be generated again. So copy and paste it into a safe location.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-2.07.27-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>PlanetScale Database Username and Password Modal</em></p>
<h3 id="heading-how-to-configure-stripe">How to Configure Stripe:</h3>
<p>To create a Stripe account, go to this <a target="_blank" href="https://dashboard.stripe.com/register">URL</a>. Once you've created the account, click on the Developer Button from the Nav menu. You'll see API keys on the left side and you'll find the Publishable key and Secret key under Standard keys.</p>
<p>Publishable key: These are the keys that can be publicly-accessible in a web or mobile app’s client-side code.</p>
<p>Secret key: This is a secret credential and should be securely stored in the server code. This key is used to call the Stripe API.</p>
<h3 id="heading-how-to-configure-nextjs-tailwindcss-and-prisma">How to Configure NextJS, TailwindCSS, and Prisma.</h3>
<p>First, we will create a NextJS app using the following command:</p>
<pre><code class="lang-shell">npx create-next-app ecommerce-tut --ts --use-npm
</code></pre>
<p>Once the project is created, open it with your favourite editor. You'll get the following structure:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-05-at-6.03.07-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Project Structure</em></p>
<p>Let's create a directory named <code>src</code>. We will move the <code>pages</code> and <code>styles</code> directory to that <code>src</code> folder. You'll get the following structure:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-2.28.16-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Project Structure after moving Pages and Styles.</em></p>
<p>Install the following packages:</p>
<pre><code class="lang-shell">npm i @ngneat/falso @prisma/client @stripe/stripe-js @tanstack/react-query currency.js next-connect react-icons react-intersection-observer stripe
</code></pre>
<p>We also need to install dev dependencies:</p>
<pre><code class="lang-shell">npm i --save-dev @tanstack/react-query-devtools autoprefixer postcss tailwindcss
</code></pre>
<p>Let's understand each of the packages:</p>
<ol>
<li><p><a target="_blank" href="https://ngneat.github.io/falso/">@ngneat/falso</a>: We will use this library to create mock data for our eCommerce website. In an ideal world, you would have an admin panel to add the products, but it is not in the scope of this tutorial.</p>
</li>
<li><p><a target="_blank" href="https://www.prisma.io/docs/concepts/components/prisma-client">@prisma/client</a>: We will use this library to connect to our database, run migrations, and do all CRUD operations on the database.</p>
</li>
<li><p><a target="_blank" href="https://stripe.com/docs/js">@stripe/stripe-js</a>: We will use this library to redirect users to the stripe checkout page and process payment.</p>
</li>
<li><p><a target="_blank" href="https://tanstack.com/query/v4/">@tanstack/react-query</a>: We will use this library for managing our asynchronous state, that is caching API responses.</p>
</li>
<li><p><a target="_blank" href="https://currency.js.org/">currency.js</a>: We will use this library for converting our prices to two decimal format.</p>
</li>
<li><p><a target="_blank" href="https://www.npmjs.com/package/next-connect">next-connect</a>: We will use this library for routing purposes on our Next API layer.</p>
</li>
<li><p><a target="_blank" href="https://react-icons.github.io/react-icons/">react-icons</a>: We will use this library for adding icons to our buttons and links.</p>
</li>
<li><p><a target="_blank" href="https://www.npmjs.com/package/react-intersection-observer">react-intersection-observer</a>: Have you seen infinite scrolling on a lot of websites and wondered how it is implemented? We will use this library to implement that based on the viewport.</p>
</li>
<li><p><a target="_blank" href="https://www.npmjs.com/package/stripe">stripe:</a> We will use the Stripe library to connect with Stripe API from our Next API layer.</p>
</li>
<li><p><a target="_blank" href="https://tanstack.com/query/v4/docs/devtools">@tanstack/react-query-devtools</a>: We will use this library as the only dev dependency to view and manage our cache during development time.</p>
</li>
<li><p><a target="_blank" href="https://www.npmjs.com/package/tailwindcss">TailwindCSS:</a> We will use this as our CSS library that also requires PostCSS and AutoPrefixer.</p>
</li>
</ol>
<p>Let's configure TailwindCSS into our project using the following command:</p>
<pre><code class="lang-shell">npx tailwindcss init -p
</code></pre>
<p>You'll get the following response:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-2.29.52-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>TailwindCSS Config Success</em></p>
<p>Now go to <code>tailwind.config.js</code> and update it with the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('tailwindcss').Config}</span> </span>*/</span>
<span class="hljs-built_in">module</span>.exports = {
    <span class="hljs-attr">content</span>: [
        <span class="hljs-string">"./src/pages/**/*.{js,ts,jsx,tsx}"</span>,
        <span class="hljs-string">"./src/components/**/*.{js,ts,jsx,tsx}"</span>,
    ],
    <span class="hljs-attr">theme</span>: {
        <span class="hljs-attr">extend</span>: {},
    },
    <span class="hljs-attr">plugins</span>: [],
};
</code></pre>
<p>To generate the CSS, Tailwind needs access to all the HTML Elements. We will be writing the UI components under pages and components only, so we pass it under content.</p>
<p>If you need to use any plugins, for example, typography, then you need to add them under the plugins array. If you need to extend the default theme provide by Tailwind, then you need to add it under <code>theme.extend</code> section.</p>
<p>Now go to <code>/src/styles/globals.css</code> and replace the existing code with the following:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<p>We will add these three directives in our <code>globals.css</code> file. The meaning of each directive is as follows:</p>
<ol>
<li><p>@tailwind base: This injects a base style provided by Tailwind.</p>
</li>
<li><p>@tailwind components: This injects classes and any other classes added by the plugin.</p>
</li>
<li><p>@tailwind utilities: This injects hover, focus, responsive, dark mode and any other utility added by the plugin.</p>
</li>
</ol>
<p>Remove the <code>Home.module.css</code> from <code>src/styles</code> directory and go to <code>src/pages/index.ts</code> and replace the existing code with the following:</p>
<pre><code class="lang-tsx">import type { NextPage } from "next";
import Head from "next/head";

const Home: NextPage = () =&gt; {
    return (
        &lt;div&gt;
            &lt;Head&gt;
                &lt;title&gt;All Products&lt;/title&gt;
                &lt;meta name="description" content="All Products" /&gt;
                &lt;link rel="icon" href="/favicon.ico" /&gt;
            &lt;/Head&gt;

            &lt;main className="container mx-auto"&gt;
                &lt;h1 className="h-1"&gt;Hello&lt;/h1&gt;
            &lt;/main&gt;
        &lt;/div&gt;
    );
};

export default Home;
</code></pre>
<p>When we run the <code>create-next-app</code> command to create the project, it adds some boilerplate code. Here we removed that in some instances while replacing <code>index.ts</code> with an <code>h1</code> and text that says "Hello".</p>
<p>It's time to run the website using the following command:</p>
<pre><code class="lang-shell">npm run dev
</code></pre>
<p>You'll get the following response:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-2.36.15-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Open <a target="_blank" href="http://localhost:3000/">http://localhost:3000</a> on your browser, and you'll get the following screen with a hello message:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-2.38.49-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Screen with Hello Message</em></p>
<p>Let's configure Prisma into our project using the following command:</p>
<pre><code class="lang-shell">npx prisma init
</code></pre>
<p>You'll get the following response:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-2.41.15-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Prisma Successfully Configured Message</em></p>
<p>Under <code>prisma/schema.prisma</code> replace the existing code with the following code:</p>
<pre><code class="lang-python">// This <span class="hljs-keyword">is</span> your Prisma schema file,
// learn more about it <span class="hljs-keyword">in</span> the docs: https://pris.ly/d/prisma-schema

generator client {
  provider        = <span class="hljs-string">"prisma-client-js"</span>
  previewFeatures = [<span class="hljs-string">"referentialIntegrity"</span>]
}

datasource db {
  provider             = <span class="hljs-string">"mysql"</span>
  url                  = env(<span class="hljs-string">"DATABASE_URL"</span>)
  referentialIntegrity = <span class="hljs-string">"prisma"</span>
}

model Category {
  id        String    @id @default(cuid())
  name      String    @unique
  createdAt DateTime  @default(now())
  products  Product[]
}

model Product {
  id          String    @id @default(cuid())
  title       String    @unique
  description String
  price       String
  quantity    Int
  image       String
  createdAt   DateTime  @default(now())
  category    Category? @relation(fields: [categoryId], references: [id])
  categoryId  String?
}
</code></pre>
<p>This file consists of our database source that is MySQL. We are using MySQL because PlanetScale supports MySQL only.</p>
<p>Also, we have created two models that are:</p>
<h3 id="heading-category">Category:</h3>
<ol>
<li><p>name: Every category will have a unique title.</p>
</li>
<li><p>createdAt: The date when a category is added.</p>
</li>
<li><p>products: A foreign relationship with the product model.</p>
</li>
</ol>
<h3 id="heading-product">Product:</h3>
<ol>
<li><p>title: Every product will have a unique title.</p>
</li>
<li><p>description: This is just information about the product.</p>
</li>
<li><p>price: It is of <code>String</code> type because it will hold a decimal value.</p>
</li>
<li><p>quantity: It is of <code>Int</code> type because it will hold a numerical value.</p>
</li>
<li><p>image: Representation of what the product will look like. We will use placeimg for the purpose of this tutorial.</p>
</li>
<li><p>createdAt: The date when a product is added.</p>
</li>
<li><p>category: A foreign relationship with the category model.</p>
</li>
</ol>
<p>We are using <code>cuid()</code> instead of <code>uuid()</code> for the id because they are better for horizontal scaling and sequential lookup performance. Prisma has inbuilt support for CUID. You can read more about it <a target="_blank" href="https://github.com/paralleldrive/cuid">here</a>.</p>
<p>Now time to update our <code>.env</code> file with the following:</p>
<pre><code class="lang-python">DATABASE_URL=

STRIPE_SECRET_KEY=

NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
</code></pre>
<p>You'll find the Stripe secret key and publishable key under the dashboard. The database URL is the one that we had copy-pasted earlier and kept in a safe location. Update this <code>.env</code> with those credentials.</p>
<p>Also, note that the <code>.gitignore</code> file created by NextJS doesn't ignore the <code>.env</code> file. It is configured to ignore the <code>.env.local</code> file. But Prisma requires <code>.env</code>, so we will replace the <code>.gitignore</code> file content with the following:</p>
<pre><code class="lang-python"><span class="hljs-comment"># See https://help.github.com/articles/ignoring-files/ for more about ignoring files.</span>

<span class="hljs-comment"># dependencies</span>
/node_modules
/.pnp
.pnp.js

<span class="hljs-comment"># testing</span>
/coverage

<span class="hljs-comment"># next.js</span>
/.next/
/out/

<span class="hljs-comment"># production</span>
/build

<span class="hljs-comment"># misc</span>
.DS_Store
*.pem

<span class="hljs-comment"># debug</span>
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

<span class="hljs-comment"># local env files</span>
.env
.env*.local

<span class="hljs-comment"># vercel</span>
.vercel

<span class="hljs-comment"># typescript</span>
*.tsbuildinfo
next-env.d.ts
</code></pre>
<p>Ideally, Prisma manages schema migration using the <code>prisma migrate</code> command. But as PlanetScale has its schema migration mechanism inbuilt, we will use that. Use the following command to push migration to our current main branch.</p>
<p>Note, our main branch is not yet promoted as a production branch.</p>
<pre><code class="lang-shell">npx prisma db push
</code></pre>
<p>Now let's generate the Prisma client using the following command:</p>
<pre><code class="lang-shell">npx prisma generate
</code></pre>
<p>Go to the PlanetScale Dashboard, and there you'll find two tables created:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-2.59.50-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>PlanetScale Two Tables Created</em></p>
<p>Click on these tables, and you'll be redirected to the following page:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-3.00.39-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>PlanetScale Database Schema</em></p>
<h2 id="heading-how-to-implement-mock-data-category-products-api-and-all-category-single-category-ui">How to Implement Mock Data, Category-Products API, and All Category-Single Category UI.</h2>
<p>In this section, we'll implement the following functionality:</p>
<ol>
<li><p>Create mock data</p>
</li>
<li><p>Create a Category and Product API.</p>
</li>
<li><p>Create an All Category and Single Category UI.</p>
</li>
</ol>
<p>You can find the <strong>eCommerce website code</strong> implemented in this section at this <a target="_blank" href="https://github.com/Sharvin26/Ecommerce-Website-ReactJS-TailwindCSS-PlanetScale-Stripe/tree/18bfb1152cfdeb14ba1a554d88d2b766a319d66a">commit</a>.</p>
<h3 id="heading-how-to-create-the-mock-data">How to Create the Mock Data:</h3>
<p>Under the <code>prisma</code> directory, create a file named <code>seed.ts</code> and copy-paste the following code:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> {
    randBetweenDate,
    randNumber,
    randProduct,
    randProductAdjective,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@ngneat/falso"</span>;
<span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@prisma/client"</span>;

<span class="hljs-keyword">const</span> primsa = <span class="hljs-keyword">new</span> PrismaClient();

<span class="hljs-keyword">const</span> main = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">await</span> primsa.category.deleteMany();
        <span class="hljs-keyword">await</span> primsa.product.deleteMany();
        <span class="hljs-keyword">const</span> fakeProducts = randProduct({
            length: <span class="hljs-number">1000</span>,
        });
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> index = <span class="hljs-number">0</span>; index &lt; fakeProducts.length; index++) {
            <span class="hljs-keyword">const</span> product = fakeProducts[index];
            <span class="hljs-keyword">const</span> productAdjective = randProductAdjective();
            <span class="hljs-keyword">await</span> primsa.product.upsert({
                where: {
                    title: <span class="hljs-string">`<span class="hljs-subst">${productAdjective}</span> <span class="hljs-subst">${product.title}</span>`</span>,
                },
                create: {
                    title: <span class="hljs-string">`<span class="hljs-subst">${productAdjective}</span> <span class="hljs-subst">${product.title}</span>`</span>,
                    description: product.description,
                    price: product.price,
                    image: <span class="hljs-string">`<span class="hljs-subst">${product.image}</span>/tech`</span>,
                    quantity: randNumber({ min: <span class="hljs-number">10</span>, max: <span class="hljs-number">100</span> }),
                    category: {
                        connectOrCreate: {
                            where: {
                                name: product.category,
                            },
                            create: {
                                name: product.category,
                                createdAt: randBetweenDate({
                                    <span class="hljs-keyword">from</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(<span class="hljs-string">"10/06/2020"</span>),
                                    to: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
                                }),
                            },
                        },
                    },
                    createdAt: randBetweenDate({
                        <span class="hljs-keyword">from</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(<span class="hljs-string">"10/07/2020"</span>),
                        to: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
                    }),
                },
                update: {},
            });
        }
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-keyword">throw</span> error;
    }
};

main().catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.warn(<span class="hljs-string">"Error While generating Seed: \n"</span>, err);
});
</code></pre>
<p>Here we are creating 1000 fake products and adding them to the database.</p>
<p>We are following these steps to add the products:</p>
<ol>
<li><p>Delete all the categories using the <code>deleteMany()</code> function.</p>
</li>
<li><p>Delete all the product using the <code>deleteMany()</code> function.</p>
</li>
<li><p>The above are optional steps, but it's always a good idea to rerun the seed script with a clean table.</p>
</li>
<li><p>As the <code>title</code> attribute from the <code>product</code> table has unique property associated with it we bind it with the <code>randProductAdjective</code> function output to make repetitions less likely.</p>
</li>
<li><p>But still, there is a probability that the title property created by the <code>falso</code> gets repeated. So we use the upsert method from <code>@prisma/client</code>.</p>
</li>
<li><p>We are also creating/associating the category when we create a product.</p>
</li>
</ol>
<p>Now go to <code>package.json</code> and update the following code below <code>scripts</code>:</p>
<pre><code class="lang-shell">"prisma": {
    "seed": "ts-node --compiler-options {\"module\":\"CommonJS\" prisma/seed.ts"
},
</code></pre>
<p>We will use the <code>ts-node</code> package to run our seed script command. The seed script is written in TypeScript while <code>ts-node</code> converts TypeScript code to JavaScript.</p>
<p>Use the following command to install the package:</p>
<pre><code class="lang-shell">npm i --save-dev ts-node
</code></pre>
<p>As the <code>ts-node</code> will convert the code to JavaScript, we can execute the following command to seed the tables with mock data:</p>
<pre><code class="lang-shell">npx prisma db seed
</code></pre>
<p>You'll get the following output that will show it has started running. It will take some time to seed the tables with mock data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-3.18.56-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Once the seed command is successful, you'll get the following response:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-3.20.09-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The benefit of Prisma is that it also has a studio, which can be used to view the database in a local development environment. Use the following command to run this studio:</p>
<pre><code class="lang-shell">npx prisma studio
</code></pre>
<p>Open <a target="_blank" href="http://localhost:5555">http://localhost:5555</a>, on your browser, and you'll get the following screen with all the tables:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-3.22.23-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Prisma Studio</em></p>
<p>The number of Products and Categories may vary on your side or be similar, as this is random data.</p>
<h3 id="heading-how-to-create-the-category-and-product-apis">How to Create the Category and Product APIs:</h3>
<p>Under the <code>src/pages/api</code> category you'll find a file named <code>hello.ts</code>. Remove this file and create two directories named <code>categories</code> and <code>products</code>.</p>
<p>Inside those categories, create a file named <code>index.ts</code> and copy-paste the following code:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { NextApiRequest, NextApiResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"next"</span>;
<span class="hljs-keyword">import</span> nc <span class="hljs-keyword">from</span> <span class="hljs-string">"next-connect"</span>;
<span class="hljs-keyword">import</span> { prisma } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../../lib/prisma"</span>;
<span class="hljs-keyword">import</span> { TApiAllCategoriesResp, TApiErrorResp } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../../types"</span>;

<span class="hljs-keyword">const</span> getCategories = <span class="hljs-keyword">async</span> (
    _req: NextApiRequest,
    res: NextApiResponse&lt;TApiAllCategoriesResp | TApiErrorResp&gt;
) =&gt; {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> categories = <span class="hljs-keyword">await</span> prisma.category.findMany({
            select: {
                id: <span class="hljs-literal">true</span>,
                name: <span class="hljs-literal">true</span>,
                products: {
                    orderBy: {
                        createdAt: <span class="hljs-string">"desc"</span>,
                    },
                    take: <span class="hljs-number">8</span>,
                    select: {
                        title: <span class="hljs-literal">true</span>,
                        description: <span class="hljs-literal">true</span>,
                        image: <span class="hljs-literal">true</span>,
                        price: <span class="hljs-literal">true</span>,
                    },
                },
            },
            orderBy: {
                createdAt: <span class="hljs-string">"desc"</span>,
            },
        });
        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json({ categories });
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).json({
            message: <span class="hljs-string">"Something went wrong!! Please try again after sometime"</span>,
        });
    }
};

<span class="hljs-keyword">const</span> handler = nc({ attachParams: <span class="hljs-literal">true</span> }).get(getCategories);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> handler;
</code></pre>
<p>In the above snippet, we are doing the following:</p>
<ol>
<li><p>When we create a file under the <code>pages&gt;api</code> directory, NextJS treats it as a Serverless API. So by creating a file named <code>categories/index.ts</code> we are informing Next that it needs to convert this to the <code>/api/categories</code> API.</p>
</li>
<li><p>Using the <code>next-connect</code> library we are making sure that only the <code>get</code> operation is allowed for the <code>getCategories</code> function.</p>
</li>
<li><p>Under this function, we are querying the database with an order as <code>desc</code> for the <code>createdAt</code> property and we only take the latest eight product rows for each category row. We also select a specific property from the product and category that are required by the front end.</p>
</li>
</ol>
<p>We don't query all the products for each category in this API, because it will slow down our response time.</p>
<p>You'll find that we have imported <code>prisma</code> and <code>types</code> files. Let's create two directories under <code>src</code> named <code>lib</code> and <code>types</code>.</p>
<p>Under the <code>lib</code> directory, create a file named <code>prisma.ts</code>, and under the types directory create a file named <code>index.ts</code>.</p>
<p>Let's create our global Prisma constant under <code>prisma.ts</code>. Copy-paste the following code:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@prisma/client"</span>;

<span class="hljs-keyword">declare</span> <span class="hljs-built_in">global</span> {
    <span class="hljs-keyword">var</span> prisma: PrismaClient;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> prisma =
    <span class="hljs-built_in">global</span>.prisma ||
    <span class="hljs-keyword">new</span> PrismaClient({
        log: [],
    });

<span class="hljs-keyword">if</span> (process.env.NODE_ENV !== <span class="hljs-string">"production"</span>) <span class="hljs-built_in">global</span>.prisma = prisma;
</code></pre>
<p>Here we are creating a global prisma variable which we can use across the project.</p>
<p>Let's add the types that we will use application-wide under <code>src/types/index.ts</code>.</p>
<p>Copy-paste the following code:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> TApiAllCategoriesResp = {
    categories: {
        id: <span class="hljs-built_in">string</span>;
        name: <span class="hljs-built_in">string</span>;
        products: {
            title: <span class="hljs-built_in">string</span>;
            description: <span class="hljs-built_in">string</span>;
            image: <span class="hljs-built_in">string</span>;
            price: <span class="hljs-built_in">string</span>;
        }[];
    }[];
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> TApiSingleCategoryWithProductResp = {
    category: {
        id: <span class="hljs-built_in">string</span>;
        name: <span class="hljs-built_in">string</span>;
        products: {
            id: <span class="hljs-built_in">string</span>;
            title: <span class="hljs-built_in">string</span>;
            description: <span class="hljs-built_in">string</span>;
            image: <span class="hljs-built_in">string</span>;
            price: <span class="hljs-built_in">string</span>;
            quantity: <span class="hljs-built_in">number</span>;
        }[];
        hasMore: <span class="hljs-built_in">boolean</span>;
    };
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> TApiSingleProductResp = {
    product: {
        title: <span class="hljs-built_in">string</span>;
        description: <span class="hljs-built_in">string</span>;
        price: <span class="hljs-built_in">string</span>;
        quantity: <span class="hljs-built_in">number</span>;
        image: <span class="hljs-built_in">string</span>;
    };
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> TApiErrorResp = {
    message: <span class="hljs-built_in">string</span>;
};
</code></pre>
<p>Here we are creating four types which will be used across the project.</p>
<p>I'll be using Postman to test this API. Postman is a utility for developing APIs. You can call the APIs, and Postman will show the response based on how you structure it.</p>
<p>Just update the URL in Postman to:</p>
<pre><code class="lang-shell">http://localhost:3000/api/categories
</code></pre>
<p>And you'll get the following response:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-3.58.53-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>All Categories Resp</em></p>
<p>Now let's create an API to get a single category's information with its products.</p>
<p>Under the <code>src/pages/api/categories</code> directory create a file named <code>[id].ts</code> and copy-paste the following code:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { NextApiRequest, NextApiResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"next"</span>;
<span class="hljs-keyword">import</span> nc <span class="hljs-keyword">from</span> <span class="hljs-string">"next-connect"</span>;
<span class="hljs-keyword">import</span> { prisma } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../../lib/prisma"</span>;
<span class="hljs-keyword">import</span> {
    TApiErrorResp,
    TApiSingleCategoryWithProductResp
} <span class="hljs-keyword">from</span> <span class="hljs-string">"../../../types"</span>;

<span class="hljs-keyword">const</span> getSingleCategory = <span class="hljs-keyword">async</span> (
    req: NextApiRequest,
    res: NextApiResponse&lt;TApiSingleCategoryWithProductResp | TApiErrorResp&gt;
) =&gt; {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> id = req.query.id <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>;
        <span class="hljs-keyword">const</span> cursorId = req.query.cursorId;
        <span class="hljs-keyword">if</span> (cursorId) {
            <span class="hljs-keyword">const</span> categoriesData = <span class="hljs-keyword">await</span> prisma.category.findUnique({
                where: {
                    id,
                },
                select: {
                    id: <span class="hljs-literal">true</span>,
                    name: <span class="hljs-literal">true</span>,
                    products: {
                        orderBy: {
                            createdAt: <span class="hljs-string">"desc"</span>,
                        },
                        take: <span class="hljs-number">12</span>,
                        skip: <span class="hljs-number">1</span>,
                        cursor: {
                            id: cursorId <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>,
                        },
                        select: {
                            id: <span class="hljs-literal">true</span>,
                            title: <span class="hljs-literal">true</span>,
                            description: <span class="hljs-literal">true</span>,
                            image: <span class="hljs-literal">true</span>,
                            price: <span class="hljs-literal">true</span>,
                            quantity: <span class="hljs-literal">true</span>,
                        },
                    },
                },
            });

            <span class="hljs-keyword">if</span> (!categoriesData) {
                <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).json({ message: <span class="hljs-string">`Category not found`</span> });
            }

            <span class="hljs-keyword">let</span> hasMore = <span class="hljs-literal">true</span>;
            <span class="hljs-keyword">if</span> (categoriesData.products.length === <span class="hljs-number">0</span>) {
                hasMore = <span class="hljs-literal">false</span>;
            }

            <span class="hljs-keyword">return</span> res
                .status(<span class="hljs-number">200</span>)
                .json({ category: { ...categoriesData, hasMore } });
        }

        <span class="hljs-keyword">const</span> categoriesData = <span class="hljs-keyword">await</span> prisma.category.findUnique({
            where: {
                id,
            },
            select: {
                id: <span class="hljs-literal">true</span>,
                name: <span class="hljs-literal">true</span>,
                products: {
                    orderBy: {
                        createdAt: <span class="hljs-string">"desc"</span>,
                    },
                    take: <span class="hljs-number">12</span>,
                    select: {
                        id: <span class="hljs-literal">true</span>,
                        title: <span class="hljs-literal">true</span>,
                        description: <span class="hljs-literal">true</span>,
                        image: <span class="hljs-literal">true</span>,
                        price: <span class="hljs-literal">true</span>,
                        quantity: <span class="hljs-literal">true</span>,
                    },
                },
            },
        });
        <span class="hljs-keyword">if</span> (!categoriesData) {
            <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).json({ message: <span class="hljs-string">`Category not found`</span> });
        }

        <span class="hljs-keyword">let</span> hasMore = <span class="hljs-literal">true</span>;
        <span class="hljs-keyword">if</span> (categoriesData.products.length === <span class="hljs-number">0</span>) {
            hasMore = <span class="hljs-literal">false</span>;
        }

        <span class="hljs-keyword">return</span> res
            .status(<span class="hljs-number">200</span>)
            .json({ category: { ...categoriesData, hasMore } });
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).json({
            message: <span class="hljs-string">"Something went wrong!! Please try again after sometime"</span>,
        });
    }
};

<span class="hljs-keyword">const</span> handler = nc({ attachParams: <span class="hljs-literal">true</span> }).get(getSingleCategory);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> handler;
</code></pre>
<p>In the above snippet, we are doing the following:</p>
<ol>
<li><p>By creating a file named <code>[id].ts</code> under <code>src/pages/api/categories</code> we are telling NextJS to convert this to the <code>/api/categories/[id]</code> API.</p>
</li>
<li><p>The <code>[id]</code> is the category id from the category table.</p>
</li>
<li><p>Using the <code>next-connect</code> library we are making sure that only the <code>get</code> operation is allowed for the <code>getSingleCategory</code> function.</p>
</li>
<li><p>Under this function, we are querying the database with order as <code>desc</code> for the <code>createdAt</code> property and we only take the latest twelve product rows. We also select a specific property from the product that is required by the front end.</p>
</li>
</ol>
<p>In this API, you will find that we have implemented pagination also. It helps us get more products under one category.</p>
<p>There are two kinds of pagination. One is cursor based, and another is offset-based pagination.</p>
<p>So why did we choose cursor-based pagination instead of offset-based pagination?</p>
<p><a target="_blank" href="https://www.prisma.io/docs/concepts/components/prisma-client/pagination">According to the Prisma docs</a>,</p>
<blockquote>
<p>"Offset pagination does not scale at a database level. For example, if you skip 200,00 records and take the first 10, the database still has to traverse the first 200,00 records before returning the 10 that you asked for - this negatively affects performance."</p>
</blockquote>
<p>For more information read this <a target="_blank" href="https://www.prisma.io/docs/concepts/components/prisma-client/pagination">helpful guide</a>.</p>
<p>Update the URL in Postman to:</p>
<pre><code class="lang-shell">http://localhost:3000/api/categories/cl91683hp006d0mvlxlg5u176?cursorId=cl91685ht00b00mvllxjwzkqk
</code></pre>
<p>Our URL consists of two ids and you'll need to add <code>cl91683hp006d0mvlxlg5u176</code> from the previous all-category response. This <code>cl91685ht00b00mvllxjwzkqk</code> id is just the cursor of the product and you can add this as the last one you want.</p>
<p>You'll get the following response:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-5.07.44-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Single Category Resp</em></p>
<p>Now let's create an API to get single product information.</p>
<p>Under the <code>src/pages/api/products</code> directory create a file named <code>[title].ts</code> and copy-paste the following code:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { NextApiRequest, NextApiResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"next"</span>;
<span class="hljs-keyword">import</span> nc <span class="hljs-keyword">from</span> <span class="hljs-string">"next-connect"</span>;
<span class="hljs-keyword">import</span> { prisma } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../../lib/prisma"</span>;
<span class="hljs-keyword">import</span> { TApiErrorResp, TApiSingleProductResp } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../../types"</span>;

<span class="hljs-keyword">const</span> getSingleProduct = <span class="hljs-keyword">async</span> (
    req: NextApiRequest,
    res: NextApiResponse&lt;TApiSingleProductResp | TApiErrorResp&gt;
) =&gt; {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> title = req.query.title <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>;
        <span class="hljs-keyword">const</span> product = <span class="hljs-keyword">await</span> prisma.product.findUnique({
            where: {
                title,
            },
            select: {
                title: <span class="hljs-literal">true</span>,
                description: <span class="hljs-literal">true</span>,
                price: <span class="hljs-literal">true</span>,
                quantity: <span class="hljs-literal">true</span>,
                image: <span class="hljs-literal">true</span>,
            },
        });
        <span class="hljs-keyword">if</span> (!product) {
            <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).json({ message: <span class="hljs-string">`Product not found`</span> });
        }
        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json({ product });
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).json({
            message: <span class="hljs-string">"Something went wrong!! Please try again after sometime"</span>,
        });
    }
};

<span class="hljs-keyword">const</span> handler = nc({ attachParams: <span class="hljs-literal">true</span> }).get(getSingleProduct);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> handler;
</code></pre>
<p>In the above snippet, we are doing the following:</p>
<ol>
<li><p>By creating a file named <code>[title].ts</code> under <code>src/pages/api/products</code> we are informing NextJS to convert this to the <code>/api/products/[title]</code> API.</p>
</li>
<li><p>The <code>[title]</code> is the product title from the product table.</p>
</li>
<li><p>Using the <code>next-connect</code> library we are making sure that only the <code>get</code> operation is allowed for the <code>getSingleProduct</code> function.</p>
</li>
<li><p>Under this function, we are querying the database using the <code>findUnique</code> query based on the title.</p>
</li>
</ol>
<p>Update the URL in Postman to:</p>
<pre><code class="lang-shell">http://localhost:3000/api/products/Practical Gorgeous Fresh Shoes
</code></pre>
<p>Here <code>Practical Gorgeous Fresh Shoes</code> is the title of the product we want to get. You can replace it with any product title from your database.</p>
<p>You'll get the following response:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-5.12.35-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Single Product Resp</em></p>
<h3 id="heading-how-to-create-the-all-category-and-single-category-uis">How to Create the All Category and Single Category UIs:</h3>
<p>Under <code>src/pages/_app.tsx</code>, replace the existing code with the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { QueryClientProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"@tanstack/react-query"</span>;
<span class="hljs-keyword">import</span> { ReactQueryDevtools } <span class="hljs-keyword">from</span> <span class="hljs-string">"@tanstack/react-query-devtools"</span>;
<span class="hljs-keyword">import</span> type { AppProps } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/app"</span>;
<span class="hljs-keyword">import</span> queryClient <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/query"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../styles/globals.css"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyApp</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">QueryClientProvider</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{queryClient}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ReactQueryDevtools</span> <span class="hljs-attr">initialIsOpen</span>=<span class="hljs-string">{false}</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">QueryClientProvider</span>&gt;</span></span>
    );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MyApp;
</code></pre>
<p>Here we are wrapping all our components with React QueryClient Provider. But we also need to pass in the Client Context.</p>
<p>Under the <code>src/lib</code> directory create a new file named <code>query.ts</code> and copy-paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { QueryClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@tanstack/react-query"</span>;

<span class="hljs-keyword">const</span> queryClient = <span class="hljs-keyword">new</span> QueryClient();

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> queryClient;
</code></pre>
<p>We are initiating a new <code>QueryClient</code> object and assigning it to the <code>queryClient</code> variable and exporting it as default. The reason we do this is that in this way we get to keep the <code>queryClient</code> object as a global context.</p>
<p>Under <code>src/pages/index.tsx</code>, replace the existing code with the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { useQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">"@tanstack/react-query"</span>;
<span class="hljs-keyword">import</span> type { NextPage } <span class="hljs-keyword">from</span> <span class="hljs-string">"next"</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> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Navbar"</span>;
<span class="hljs-keyword">import</span> ProductGrid <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/ProductGrid"</span>;
<span class="hljs-keyword">import</span> Skelton <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Skelton"</span>;

<span class="hljs-keyword">const</span> Home: NextPage = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> getAllCategories = <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> respJSON = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"/api/categories"</span>);
            <span class="hljs-keyword">const</span> resp = <span class="hljs-keyword">await</span> respJSON.json();
            <span class="hljs-keyword">return</span> resp;
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-keyword">throw</span> error;
        }
    };

    <span class="hljs-keyword">const</span> { isLoading, data } = useQuery(
        [<span class="hljs-string">"AllCategoreiesWithProducts"</span>],
        getAllCategories
    );

    <span class="hljs-keyword">const</span> categories = data?.categories;

    <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>All Products<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"All Products"</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"container mx-auto"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
                {isLoading ? (
                    <span class="hljs-tag">&lt;<span class="hljs-name">Skelton</span> /&gt;</span>
                ) : (
                    <span class="hljs-tag">&lt;&gt;</span>
                        {categories &amp;&amp; categories?.length &gt; 0 &amp;&amp; (
                            <span class="hljs-tag">&lt;<span class="hljs-name">ProductGrid</span>
                                <span class="hljs-attr">showLink</span>=<span class="hljs-string">{true}</span>
                                <span class="hljs-attr">categories</span>=<span class="hljs-string">{categories}</span>
                            /&gt;</span>
                        )}
                    <span class="hljs-tag">&lt;/&gt;</span>
                )}
            <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
        &lt;/div&gt;
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Let's understand our code.</p>
<p>Here we are fetching the data from the <code>/api/categories</code> endpoint that we wrote earlier. We are using <code>useQuery</code> to cache this data with the key <code>AllCategoreiesWithProducts</code>.</p>
<p>But there are three components that we haven't created yet. Let's create those and understand each one.</p>
<p>Under the <code>src</code> directory, create a <code>components</code> directory. Under the newly created <code>components</code> directory, create three files named <code>Navbar.tsx</code>, <code>ProductGrid.tsx</code> and <code>Skelton.tsx</code>.</p>
<p>Under <code>Navbar.tsx</code> copy-paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> NextLink <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</span>;

<span class="hljs-keyword">const</span> Navbar = <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">"relative bg-white mx-6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-between pt-6 md:justify-start md:space-x-10"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-start lg:w-0 lg:flex-1"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">NextLink</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"cursor-pointer"</span>&gt;</span>
                            Ecomm App
                        <span class="hljs-tag">&lt;/<span class="hljs-name">NextLink</span>&gt;</span>
                    <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 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> Navbar;
</code></pre>
<p>Here we have created an <code>h1</code> with the text as Ecomm App. We have wrapped this text around <code>NextLink</code> and set the location as <code>/</code>. So when user clicks on this, they will be redirected to the home page.</p>
<p>Under <code>ProductGrid.tsx</code> copy-paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> NextImage <span class="hljs-keyword">from</span> <span class="hljs-string">"next/image"</span>;
<span class="hljs-keyword">import</span> NextLink <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</span>;
<span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { AiOutlineRight } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/ai"</span>;
<span class="hljs-keyword">import</span> { useInView } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-intersection-observer"</span>;
<span class="hljs-keyword">import</span> { TApiAllCategoriesResp } <span class="hljs-keyword">from</span> <span class="hljs-string">"../types"</span>;

interface IProductGrid <span class="hljs-keyword">extends</span> TApiAllCategoriesResp {
    <span class="hljs-attr">showLink</span>: boolean;
    hasMore?: boolean;
    loadMoreFun?: <span class="hljs-built_in">Function</span>;
}

<span class="hljs-keyword">const</span> ProductGrid = <span class="hljs-function">(<span class="hljs-params">props: IProductGrid</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { categories, showLink, loadMoreFun, hasMore } = props;
    <span class="hljs-keyword">const</span> { ref, inView } = useInView();

    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (inView) {
            <span class="hljs-keyword">if</span> (loadMoreFun) loadMoreFun();
        }
    }, [inView, loadMoreFun]);

    <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">"bg-white"</span>&gt;</span>
            {categories.map((category) =&gt; (
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-12  p-6"</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{category.name}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-row justify-between"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"inline-flex items-center rounded-md bg-sky-800 px-8 py-2 text-md font-medium text-white"</span>&gt;</span>
                            {category.name}
                        <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                        {showLink &amp;&amp; (
                            <span class="hljs-tag">&lt;<span class="hljs-name">NextLink</span> <span class="hljs-attr">href</span>=<span class="hljs-string">{</span>`/<span class="hljs-attr">category</span>/${<span class="hljs-attr">category.id</span>}`}&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-row gap-2 underline hover:cursor-pointer items-center"</span>&gt;</span>
                                    View More
                                    <span class="hljs-tag">&lt;<span class="hljs-name">AiOutlineRight</span> /&gt;</span>
                                <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">NextLink</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">"mt-6  grid grid-cols-1 gap-y-10 gap-x-6 xl:gap-x-8 sm:grid-cols-2 lg:grid-cols-4"</span>&gt;</span>
                        {category?.products.map((product) =&gt; (
                            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
                                <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6 group rounded-lg border border-gray-200 bg-neutral-200"</span>
                                <span class="hljs-attr">key</span>=<span class="hljs-string">{product.title}</span>
                            &gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"min-h-80 w-full overflow-hidden rounded-md group-hover:opacity-75 lg:aspect-none lg:h-80"</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">NextImage</span>
                                        <span class="hljs-attr">priority</span>=<span class="hljs-string">{true}</span>
                                        <span class="hljs-attr">layout</span>=<span class="hljs-string">"responsive"</span>
                                        <span class="hljs-attr">width</span>=<span class="hljs-string">"25"</span>
                                        <span class="hljs-attr">height</span>=<span class="hljs-string">"25"</span>
                                        <span class="hljs-attr">src</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">product.image</span>}`}
                                        <span class="hljs-attr">alt</span>=<span class="hljs-string">{product.title}</span>
                                        <span class="hljs-attr">className</span>=<span class="hljs-string">"h-full w-full object-cover object-center lg:h-full lg:w-full"</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">"relative mt-2"</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-sm font-medium text-gray-900"</span>&gt;</span>
                                        {product.title}
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-1 text-sm text-gray-500"</span>&gt;</span>
                                        {product.price}
                                    <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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-6"</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">NextLink</span>
                                        <span class="hljs-attr">href</span>=<span class="hljs-string">{</span>`/<span class="hljs-attr">product</span>/${<span class="hljs-attr">product.title</span>}`}
                                    &gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative flex items-center justify-center rounded-md border border-transparent bg-sky-800 py-2 px-8 text-sm font-medium text-white hover:bg-sky-900 hover:cursor-pointer"</span>&gt;</span>
                                            View More Details
                                        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">NextLink</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>
                    {!showLink &amp;&amp; (
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-center mt-8"</span>&gt;</span>
                            {hasMore ? (
                                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                                    <span class="hljs-attr">ref</span>=<span class="hljs-string">{ref}</span>
                                    <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
                                    <span class="hljs-attr">className</span>=<span class="hljs-string">"inline-flex items-center rounded-md border border-transparent bg-sky-800 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-sky-900"</span>
                                &gt;</span>
                                    Loading...
                                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                            ) : (
                                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"border-l-4 border-yellow-400 bg-yellow-50 p-4 w-full"</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex"</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"ml-3"</span>&gt;</span>
                                            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-sm text-yellow-700"</span>&gt;</span>
                                                You have viewed all the Products
                                                under this category.
                                            <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">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>
                    )}
                    {showLink &amp;&amp; (
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full border-b border-gray-300 mt-24"</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> ProductGrid;
</code></pre>
<p>Here we have created a grid that will show 1 column for the base screen. For the sm screen it will show 2 columns and for the lg screen it will show 4 columns.</p>
<p>Under this, we have a single card which has a Title, Price, and View More Details button. The View More Details button redirects the user to a single product page which will create a bit later.</p>
<p>Apart from that, we are using the <code>useInView</code> hook from the <code>react-intersection-observer</code> library to find the user's cursor on the screen. This ref is attached to a <code>Loading...</code> button and once user is near it then we execute the <code>loadMoreFn</code> function.</p>
<p>It makes an API call to the server to get the next twelve rows from the last cursor.</p>
<p>Under <code>Skelton.tsx</code> copy-paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Skelton = <span class="hljs-function">() =&gt;</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-12 h-8 w-40 rounded-lg bg-gray-200"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-6 grid grid-cols-1 gap-y-10 gap-x-6 sm:grid-cols-2 lg:grid-cols-4 xl:gap-x-8"</span>&gt;</span>
                {Array(16)
                    .fill(0)
                    .map((_val, index) =&gt; (
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"rounded-2xl bg-black/5 p-4"</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"h-60 rounded-lg bg-gray-200"</span> /&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-4 mt-6 mb-4"</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"h-3 w-3/5 rounded-lg bg-gray-200"</span> /&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"h-3 w-4/5 rounded-lg bg-gray-200"</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;/&gt;</span></span>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Skelton;
</code></pre>
<p>We are using <code>placeimg</code> to get fake images for our product and we are using the Next Image component which requires that it be mentioned under <code>next.config.js</code>.</p>
<p>Replace the existing code in <code>next.config.js</code> with the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('next').NextConfig}</span> </span>*/</span>
<span class="hljs-keyword">const</span> nextConfig = {
    <span class="hljs-attr">reactStrictMode</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">swcMinify</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">images</span>: {
        <span class="hljs-attr">domains</span>: [<span class="hljs-string">"placeimg.com"</span>],
    },
};

<span class="hljs-built_in">module</span>.exports = nextConfig
</code></pre>
<p>We will need to restart our server. Use the following command to start your development server again:</p>
<pre><code class="lang-shell">npm run dev
</code></pre>
<p>Open <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> and you'll see the following UI:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-5.31.29-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>All Products Page</em></p>
<p>Now let's create a single category page that the user can go to using a <code>View More</code> link.</p>
<p>Under <code>src/pages</code> create a directory named <code>category</code>. Under this directory create a file named <code>[id].tsx</code> and copy paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { useInfiniteQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">"@tanstack/react-query"</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> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/Navbar"</span>;
<span class="hljs-keyword">import</span> ProductGrid <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/ProductGrid"</span>;
<span class="hljs-keyword">import</span> Skelton <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/Skelton"</span>;

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

    <span class="hljs-keyword">const</span> getSingleCategory = <span class="hljs-keyword">async</span> ({ pageParam = <span class="hljs-literal">null</span> }) =&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">let</span> url = <span class="hljs-string">`/api/categories/<span class="hljs-subst">${router.query.id}</span>`</span>;
            <span class="hljs-keyword">if</span> (pageParam) {
                url += <span class="hljs-string">`?cursorId=<span class="hljs-subst">${pageParam}</span>`</span>;
            }
            <span class="hljs-keyword">const</span> respJSON = <span class="hljs-keyword">await</span> fetch(url);
            <span class="hljs-keyword">const</span> resp = <span class="hljs-keyword">await</span> respJSON.json();
            <span class="hljs-keyword">return</span> resp;
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-keyword">throw</span> error;
        }
    };

    <span class="hljs-keyword">const</span> { isLoading, data, fetchNextPage, isError } = useInfiniteQuery(
        [<span class="hljs-string">`singleCategory <span class="hljs-subst">${router.query.id <span class="hljs-keyword">as</span> string}</span>`</span>],
        getSingleCategory,
        {
            <span class="hljs-attr">enabled</span>: !!router.query.id,
            <span class="hljs-attr">getNextPageParam</span>: <span class="hljs-function">(<span class="hljs-params">lastPage</span>) =&gt;</span> {
                <span class="hljs-keyword">const</span> nextCursor =
                    lastPage?.category?.products[
                        lastPage?.category?.products?.length - <span class="hljs-number">1</span>
                    ]?.id;
                <span class="hljs-keyword">return</span> nextCursor;
            },
        }
    );

    <span class="hljs-keyword">const</span> allProductsWithCategory: any = {
        <span class="hljs-attr">name</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">products</span>: [],
        <span class="hljs-attr">hasMore</span>: <span class="hljs-literal">true</span>,
    };

    data?.pages.map(<span class="hljs-function">(<span class="hljs-params">page</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (page?.category) {
            <span class="hljs-keyword">if</span> (page.category?.name) {
                allProductsWithCategory.name = page.category?.name;
            }
            <span class="hljs-keyword">if</span> (page.category?.products &amp;&amp; page.category?.products.length &gt; <span class="hljs-number">0</span>) {
                allProductsWithCategory.products.push(
                    ...page.category?.products
                );
            }
        }
        <span class="hljs-keyword">return</span> page?.category;
    });

    <span class="hljs-keyword">if</span> (data?.pages[data?.pages.length - <span class="hljs-number">1</span>]?.category?.products.length === <span class="hljs-number">0</span>) {
        allProductsWithCategory.hasMore = <span class="hljs-literal">false</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>
                    {isLoading
                        ? "Loading..."
                        : `All ${allProductsWithCategory?.name} Product`}
                <span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">meta</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
                    <span class="hljs-attr">content</span>=<span class="hljs-string">"Generated by create next app"</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"container mx-auto"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
                {isLoading ? (
                    <span class="hljs-tag">&lt;<span class="hljs-name">Skelton</span> /&gt;</span>
                ) : (
                    <span class="hljs-tag">&lt;&gt;</span>
                        {allProductsWithCategory &amp;&amp;
                            allProductsWithCategory.products.length &gt; 0 &amp;&amp; (
                                <span class="hljs-tag">&lt;<span class="hljs-name">ProductGrid</span>
                                    <span class="hljs-attr">hasMore</span>=<span class="hljs-string">{allProductsWithCategory.hasMore}</span>
                                    <span class="hljs-attr">showLink</span>=<span class="hljs-string">{false}</span>
                                    <span class="hljs-attr">categories</span>=<span class="hljs-string">{[allProductsWithCategory]}</span>
                                    <span class="hljs-attr">loadMoreFun</span>=<span class="hljs-string">{fetchNextPage}</span>
                                /&gt;</span>
                            )}
                    <span class="hljs-tag">&lt;/&gt;</span>
                )}
            <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
        &lt;/div&gt;
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> SingleCategory;
</code></pre>
<p>Here we are calling the <code>/api/categories/[id]</code> API to get the latest twelve products for that category id.</p>
<p>We are using the <code>useInfiniteQuery</code> hook from <code>react query</code> to fetch the data. This hook is useful for cursor-based pagination. We will be using the <code>ProductGrid</code> component that we created earlier.</p>
<p>Open <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a>, click on the View More link for any of the category, and you'll see the following UI:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-5.38.25-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Single Category Page</em></p>
<p>The difference between the previous UI and the current is that we now don't have the View More Link in the top right corner. Also, when you scroll below, you'll get more products for that category.</p>
<p>Once we scroll through all the products in that category we will see the following warning alert:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-5.39.44-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-implement-single-product-ui-and-stripe-checkout">How to Implement Single Product UI and Stripe Checkout.</h2>
<p>In this section, we'll implement the following functionality:</p>
<ol>
<li><p>Create Single Product UI</p>
</li>
<li><p>Create Stripe Checkout</p>
</li>
</ol>
<p>You can find the <strong>eCommerce</strong> website <strong>code</strong> implemented in this section at this <a target="_blank" href="https://github.com/Sharvin26/Ecommerce-Website-ReactJS-TailwindCSS-PlanetScale-Stripe/tree/e4b5426423358479a5bbe91ba17b3febacd5e4a3">commit</a>.</p>
<h3 id="heading-how-to-create-the-single-product-ui">How to Create the Single Product UI:</h3>
<p>Under the <code>src/pages</code> directory create a directory named <code>product</code>.</p>
<p>Under this directory create a file named <code>[title].tsx</code> and copy-paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { loadStripe, Stripe } <span class="hljs-keyword">from</span> <span class="hljs-string">"@stripe/stripe-js"</span>;
<span class="hljs-keyword">import</span> { useMutation, useQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">"@tanstack/react-query"</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> NextImage <span class="hljs-keyword">from</span> <span class="hljs-string">"next/image"</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> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/Navbar"</span>;
<span class="hljs-keyword">import</span> Skelton <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/Skelton"</span>;

<span class="hljs-keyword">const</span> stripePromiseclientSide = loadStripe(
    process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!
);

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

    <span class="hljs-keyword">const</span> getSingleProduct = <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> title = router?.query?.title;

            <span class="hljs-keyword">const</span> respJSON = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`/api/products/<span class="hljs-subst">${title}</span>`</span>);
            <span class="hljs-keyword">const</span> resp = <span class="hljs-keyword">await</span> respJSON.json();
            <span class="hljs-keyword">return</span> resp;
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-keyword">throw</span> error;
        }
    };

    <span class="hljs-keyword">const</span> { mutate, <span class="hljs-attr">isLoading</span>: mutationIsLoading } = useMutation(
        <span class="hljs-keyword">async</span> (body: any) =&gt; {
            <span class="hljs-keyword">try</span> {
                <span class="hljs-keyword">const</span> respJSON = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"/api/create-checkout-session"</span>, {
                    <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
                    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(body),
                });
                <span class="hljs-keyword">const</span> resp = <span class="hljs-keyword">await</span> respJSON.json();
                <span class="hljs-keyword">const</span> stripe = (<span class="hljs-keyword">await</span> stripePromiseclientSide) <span class="hljs-keyword">as</span> Stripe;
                <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> stripe.redirectToCheckout({
                    <span class="hljs-attr">sessionId</span>: resp.id,
                });
                <span class="hljs-keyword">return</span> result;
            } <span class="hljs-keyword">catch</span> (error) {
                <span class="hljs-keyword">throw</span> error;
            }
        }
    );

    <span class="hljs-keyword">const</span> { data, isLoading } = useQuery(
        [<span class="hljs-string">`singleProduct, <span class="hljs-subst">${router?.query?.title}</span>`</span>],
        getSingleProduct,
        {
            <span class="hljs-attr">enabled</span>: !!router?.query?.title,
        }
    );

    <span class="hljs-keyword">const</span> product = data?.product;

    <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>{isLoading ? "Loading..." : `${product?.title}`}<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">meta</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
                    <span class="hljs-attr">content</span>=<span class="hljs-string">"Generated by create next app"</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"container mx-6 md:mx-auto"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
                {isLoading ? (
                    <span class="hljs-tag">&lt;<span class="hljs-name">Skelton</span> /&gt;</span>
                ) : (
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"pt-6 pb-16 sm:pb-24"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mx-auto mt-8"</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col md:flex-row gap-x-8"</span>&gt;</span>
                                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"min-h-80 w-full overflow-hidden rounded-md group-hover:opacity-75 lg:aspect-none lg:h-80"</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">NextImage</span>
                                            <span class="hljs-attr">layout</span>=<span class="hljs-string">"responsive"</span>
                                            <span class="hljs-attr">width</span>=<span class="hljs-string">"25"</span>
                                            <span class="hljs-attr">height</span>=<span class="hljs-string">"25"</span>
                                            <span class="hljs-attr">src</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">product.image</span>}`}
                                            <span class="hljs-attr">alt</span>=<span class="hljs-string">{product.title}</span>
                                            <span class="hljs-attr">className</span>=<span class="hljs-string">"h-full w-full object-cover object-center lg:h-full lg:w-full"</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">"lg:col-span-5 lg:col-start-8 mt-8 md:mt-0"</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-medium text-gray-900 "</span>&gt;</span>
                                            {product.title}
                                        <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-light text-gray-700 mt-4"</span>&gt;</span>
                                            {product.description}
                                        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-normal text-gray-500 mt-4"</span>&gt;</span>
                                            USD {product.price}
                                        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                                            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                                                mutate({
                                                    title: product.title,
                                                    image: product.image,
                                                    description:
                                                        product.description,
                                                    price: product.price,
                                                })
                                            }
                                            disabled={mutationIsLoading}
                                            type="button"
                                            className="inline-flex items-center rounded-md border border-transparent bg-sky-800 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-sky-900  mt-4"
                                        &gt;
                                            Buy Now
                                        <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">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">main</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> SingleProduct;
</code></pre>
<p>Here we are calling <code>/api/products/title</code> API to get the latest product. We have also created Stripe Interface for creating a checkout method once a user clicks the Buy Now button.</p>
<p>Once the user clicks the Buy Now button, we make an API call to <code>/api/create-checkout-session</code> using the <code>useMutation</code> hook. On a successful response, we redirect the user to the Stripe default checkout page.</p>
<p>Open <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> and click on View More Details button for any product.</p>
<p>You'll see the following UI:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-5.54.40-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Single Product Page</em></p>
<p>You can also visit this page by clicking on the View More link and then clicking on the View More Details button for any product.</p>
<h3 id="heading-how-to-set-up-stripe-checkout">How to Set Up Stripe Checkout:</h3>
<p>To set up Stripe Checkout, we need to add a new file under the lib directory.</p>
<p>Create a new file named <code>stripe.ts</code> under the lib directory and copy paste the following code:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> Stripe <span class="hljs-keyword">from</span> <span class="hljs-string">"stripe"</span>;

<span class="hljs-keyword">const</span> stripeServerSide = <span class="hljs-keyword">new</span> Stripe(process.env.STRIPE_SECRET_KEY!, {
    apiVersion: <span class="hljs-string">"2022-08-01"</span>,
});

<span class="hljs-keyword">export</span> { stripeServerSide };
</code></pre>
<p>Here we are creating server-side instances of Stripe. Now under the <code>pages/api</code> directory, create a new file named <code>create-checkout-session.ts</code> and copy-paste the following code:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> currency <span class="hljs-keyword">from</span> <span class="hljs-string">"currency.js"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { NextApiRequest, NextApiResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"next"</span>;
<span class="hljs-keyword">import</span> nc <span class="hljs-keyword">from</span> <span class="hljs-string">"next-connect"</span>;
<span class="hljs-keyword">import</span> { stripeServerSide } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../lib/stripe"</span>;
<span class="hljs-keyword">import</span> { TApiErrorResp } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../types"</span>;

<span class="hljs-keyword">const</span> checkoutSession = <span class="hljs-keyword">async</span> (
    req: NextApiRequest,
    res: NextApiResponse&lt;<span class="hljs-built_in">any</span> | TApiErrorResp&gt;
) =&gt; {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> host = req.headers.origin;
        <span class="hljs-keyword">const</span> referer = req.headers.referer;
        <span class="hljs-keyword">const</span> body = <span class="hljs-built_in">JSON</span>.parse(req.body);
        <span class="hljs-keyword">const</span> formatedPrice = currency(body.price, {
            precision: <span class="hljs-number">2</span>,
            symbol: <span class="hljs-string">""</span>,
        }).multiply(<span class="hljs-number">100</span>);
        <span class="hljs-keyword">const</span> session = <span class="hljs-keyword">await</span> stripeServerSide.checkout.sessions.create({
            mode: <span class="hljs-string">"payment"</span>,
            payment_method_types: [<span class="hljs-string">"card"</span>],
            line_items: [
                {
                    price_data: {
                        currency: <span class="hljs-string">"usd"</span>,
                        product_data: {
                            name: body?.title,
                            images: [body.image],
                            description: body?.description,
                        },
                        unit_amount_decimal: formatedPrice.toString(),
                    },
                    quantity: <span class="hljs-number">1</span>,
                },
            ],
            success_url: <span class="hljs-string">`<span class="hljs-subst">${host}</span>/thank-you`</span>,
            cancel_url: <span class="hljs-string">`<span class="hljs-subst">${referer}</span>?status=cancel`</span>,
        });
        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json({ id: session.id });
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).json({
            message: <span class="hljs-string">"Something went wrong!! Please try again after sometime"</span>,
        });
    }
};

<span class="hljs-keyword">const</span> handler = nc({ attachParams: <span class="hljs-literal">true</span> }).post(checkoutSession);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> handler;
</code></pre>
<p>In the snippet above we are doing the following:</p>
<ol>
<li><p>Formatting the price with precision as two and multiplying it by 100 as Stripe expects the unit_amount in cents by default.</p>
</li>
<li><p>We create the session and pass the id as the response.</p>
</li>
</ol>
<p>Now we need to create another page named <code>thank-you.tsx</code> under the <code>src/pages</code> directory. Once the product purchase is successful, Stripe Checkout will redirect to this page.</p>
<p>Copy-paste the following code under this file:</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">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/router"</span>;
<span class="hljs-keyword">import</span> { HiCheckCircle } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/hi"</span>;
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Navbar"</span>;

<span class="hljs-keyword">const</span> ThankYou = <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;<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>Thank You<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"All Products"</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"container mx-auto"</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"rounded-md bg-green-50 p-4 mt-8"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex-shrink-0"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">HiCheckCircle</span>
                                <span class="hljs-attr">className</span>=<span class="hljs-string">"h-5 w-5 text-green-400"</span>
                                <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</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">"ml-3"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-sm font-medium text-green-800"</span>&gt;</span>
                                Order Placed
                            <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">"mt-2 text-sm text-green-700"</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
                                    Thank you for your Order. We have placed the
                                    order and your email will recieve further
                                    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>
                            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> router.push("/")}
                                type="button"
                                className="inline-flex items-center rounded-md border border-transparent bg-sky-800 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-sky-900 mt-4"
                            &gt;
                                Continue Shopping
                            <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">div</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">div</span>&gt;</span></span>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ThankYou;
</code></pre>
<p>Open <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> and click on the View More Details button of any product.</p>
<p>Click on the Buy Now button and you'll be redirected to the following page:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-6.09.52-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Add all the details for the test card. You can use any card from this <a target="_blank" href="https://stripe.com/docs/testing?numbers-or-method-or-token=card-numbers#cards">link</a>. Stripe provides various test cards which work only during Test Mode. Once you click on Pay and payment processing happens, Stripe will redirect you to the success page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-09-at-6.14.51-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Thank You Page</em></p>
<h2 id="heading-how-to-deploy-the-website-to-production">How to Deploy the Website to Production</h2>
<p>In this section, we'll implement the following functionality:</p>
<ol>
<li><p>Promote our PlanetScale branch to Main.</p>
</li>
<li><p>Deploy the app on Vercel.</p>
</li>
</ol>
<h3 id="heading-how-to-promote-the-planetscale-branch-to-main">How to Promote the PlanetScale Branch to Main:</h3>
<p>To promote the branch to main, we can do it either via the terminal or dashboard. I'll use the dashboard for this tutorial.</p>
<p>Go to your project on PlanetScale and you'll find the following message on the dashboard:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-10-at-4.19.14-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>PlanetScale Database Promotion</em></p>
<p>Let's click on the Promote a branch to production button and you'll get a confirmation model. Click on the Promote branch button. Once done you'll get a toast with a success message.</p>
<h3 id="heading-how-to-deploy-to-vercel">How to Deploy to Vercel:</h3>
<p>If you don't have an account on Vercel, you can create one <a target="_blank" href="https://vercel.com/signup">here</a>.</p>
<p>You can create a project on GitHub and push it to the Main branch. If you don't know how, you can check out <a target="_blank" href="https://docs.github.com/en/get-started/importing-your-projects-to-github/importing-source-code-to-github/adding-locally-hosted-code-to-github#adding-a-local-repository-to-github-using-git">this tutorial</a>.</p>
<p>Once the project is pushed on GitHub, go to Vercel and create an Add New button and select Project from the drop down.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-10-at-4.26.04-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Add New Project Vercel</em></p>
<p>You'll get the following the UI:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-10-at-4.26.39-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Select Git Provider Vercel</em></p>
<p>As we have pushed the code on GitHub, let's click on the Continue with GitHub button. You'll get the following UI:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-10-at-4.28.03-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Select Git Repository Vercel</em></p>
<p>Click on Import and you'll get the following UI:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-10-at-4.29.39-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Configure Project Vercel</em></p>
<p>Click on the Environment Variables and add these three there:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-10-at-4.31.02-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Add NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY, STRIPE_SECRET_KEY, and DATABASE_URL</em></p>
<p>Once done click the Deploy button. You'll get the following UI once the deployment starts:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-10-at-4.31.52-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Deploying Vercel</em></p>
<p>Once deployed, Vercel will give you a Unique URL.</p>
<p>Visit this URL and you'll find its failing. Let's go to the deployment &gt; functions and you'll see the following error:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-2022-10-10-at-4.38.08-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Prisma generate Fails</em></p>
<p>We need to update our build command in <code>package.json</code> as follows:</p>
<pre><code class="lang-shell">"build": "npx prisma generate &amp;&amp; next build",
</code></pre>
<p>Push the code again to the Git repository and you'll find that Vercel starts redeploying your project.</p>
<p>Once the deployment is done, you can visit your application URL and you'll find it shows all your products.</p>
<p>With this, we have created our production-ready eCommerce application. If you have built the website along with the tutorial, then a very big congratulations to you on this achievement.</p>
<h2 id="heading-thank-you-for-reading"><strong>Thank you for reading!</strong></h2>
<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 (<a target="_blank" href="https://twitter.com/sharvinshah26">@sharvinshah26</a> ).</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a TodoApp using ReactJS, NextJS, and Supabase ]]>
                </title>
                <description>
                    <![CDATA[ Hello folks, welcome to this tutorial. Today we're going to build a production-ready Todo application with React, Next, and Supabase. Before we begin, you should be familiar with the basics of React.js and Next.js to get the most out of this guide. I... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-todoapp-using-react-and-supabase/</link>
                <guid isPermaLink="false">66d460f6ffe6b1f641b5fa87</guid>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sharvin Shah ]]>
                </dc:creator>
                <pubDate>Tue, 07 Dec 2021 15:48:26 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/12/Screenshot-2021-12-04-at-6.06.45-PM-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hello folks, welcome to this tutorial. Today we're going to build a production-ready Todo application with React, Next, and Supabase.</p>
<p>Before we begin, you should be familiar with the basics of <strong>React.js</strong> and <strong>Next.js</strong> to get the most out of this guide.</p>
<p>If you're not and need to brush up, I would recommend that you go through the <a target="_blank" href="https://reactjs.org/docs/getting-started.html">ReactJS documentation</a> and <a target="_blank" href="https://nextjs.org/docs/getting-started">NextJS documentation</a>.</p>
<h2 id="heading-heres-what-were-going-to-build"><strong>Here's what we're going to build</strong></h2>
<p>We'll build a ToDo app that looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Screenshot-2021-12-04-at-5.49.41-PM.png" 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><a target="_blank" href="https://reactjs.org/docs/getting-started.html">ReactJS</a>: a JavaScript library for building user interfaces. It is declarative and component-based.</p>
</li>
<li><p><a target="_blank" href="https://nextjs.org/docs/getting-started">NextJS</a>: a React-based framework that lets us render data on the server-side. It helps Google crawl the application which results in SEO benefits.</p>
</li>
<li><p><a target="_blank" href="https://supabase.io/docs">Supabase</a>: provides authentication, database, and storage that we are going to use in our application.</p>
</li>
<li><p><a target="_blank" href="https://chakra-ui.com/docs/getting-started">Chakra UI</a>: is a simple, modular, and accessible component library that will provide us with the building blocks to build the application.</p>
</li>
<li><p><a target="_blank" href="https://vercel.com/docs">Vercel</a>: will host our application. It scales well, all without any configuration, and deployment is instant.</p>
</li>
</ol>
<h2 id="heading-why-use-supabase">Why use Supabase?</h2>
<p>According to the Supabase documentation, Supabase is <em>"an open source Firebase alternative".</em></p>
<p>However, Supabase is not completely similar to Firebase. The difference between the two is that Supabase uses <strong>Postgres</strong> (a relational database) for storing data whereas Firebase uses the <strong>NoSQL</strong> mechanism to store data.</p>
<p>Personally, I typically use Postgres as my primary database and I have found it to scale well.</p>
<p>Supabase provides the following services:</p>
<ol>
<li><p><strong>Authentication</strong></p>
</li>
<li><p><strong>Postgres database</strong></p>
</li>
<li><p><strong>Real time rest server</strong></p>
</li>
<li><p><strong>Row level security</strong></p>
</li>
<li><p><strong>Storage bucket</strong></p>
</li>
</ol>
<p>Now let's understand how it works:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-17-at-1.12.37-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Architectural Diagram from Supabase documentation</em></p>
<p>Alright, what's going on here?</p>
<p>As you already know, <strong>Supabase</strong> uses Postgres as a database – but it also has many other components which provide different services.</p>
<p>One of my favorites is <strong>Realtime</strong>. Supabase uses the Elixir server to set up a web socket connection to listen for insert, update, and delete the events.</p>
<p><strong>PostgRest</strong> directly converts the Postgres database into a Rest API.</p>
<p><strong>GoTrue</strong> is an API for managing users and issuing SWT tokens.</p>
<p><strong>Postgres-Meta</strong> is a Restful API for managing the Postgres database.</p>
<p><strong>Kong</strong> is an API gateway.</p>
<blockquote>
<p><strong>Note:</strong> All these definitions are taken from the supabase documentation. To read more about how Supabase works, you can visit their <a target="_blank" href="https://supabase.io/docs">documentation</a>.</p>
</blockquote>
<p>And with that, we're ready to dive into our project. Here's what we'll cover:</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-how-to-configure-supabase-tables-auth-and-storage">How to configure Supabase tables, auth, and storage</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-sign-in-using-supabase">How to implement sign-in using Supabase</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-show-all-todos-add-new-todos-and-update-and-delete-todos">How to show all todos, add new todos, and update and delete todos</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-update-profile-details-and-avatars">How to update profile details and avatar</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-deploy-the-app-to-vercel-and-configure-supabase-authentication">How to deploy the app to Vercel and configure Supabase authentication</a></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, then it is available in this <a target="_blank" href="https://github.com/Sharvin26/TodoApp-supabase">repository</a>.</p>
<h2 id="heading-how-to-configure-supabase-tables-auth-and-storage">How to Configure Supabase Tables, Auth, and Storage</h2>
<p>In this section, we'll implement the following functionality:</p>
<ol>
<li><p><strong>Create a Supabase project.</strong></p>
</li>
<li><p><strong>Setup authentication for users and policies.</strong></p>
</li>
<li><p><strong>Configure database and policies for users and todos.</strong></p>
</li>
</ol>
<p>To create a Supabase project, visit the following <a target="_blank" href="https://supabase.io/">link</a>. Click on the "Start your project" button and login via GitHub (at the time of writing this article, they only support GitHub as an auth provider).</p>
<p>Once you've created your account, click on New project where it will ask for the organization. By default, Supabase will create an organizational account for you with your username. I'll be using the default but you can create your own for this project.</p>
<p>Once the organization is selected, Supabase will ask for the project name, database password, and region.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-17-at-12.34.24-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Supabase Create Project</em></p>
<p>Fill out this form and click on the <strong>Create new project</strong> button.</p>
<p>Supabase will start setting up the application. It may take a few minutes to set up.</p>
<p>Under the Project API keys section, you'll see two types of keys:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-17-at-12.48.10-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Supabase Project API Keys</em></p>
<p><strong>anon</strong> is a public API key and it can be used on the client-side.</p>
<p><strong>service_role</strong> is a private API key and you use it on the server-side only. This key can bypass the row-level security and mutate the data.</p>
<h3 id="heading-what-is-row-level-security-in-supabase">What is Row Level Security in Supabase?</h3>
<p>You might be wondering – what is row-level security and why it is so important?</p>
<p>Well, Supabase has a client library to access data directly from the browser and for that, we use the <strong>anon</strong> key. As the anon key is on the client, anyone can have access to the key via the network tab.</p>
<p>But there are some cases where we don't want the data to be directly accessed by the browser using the client library.</p>
<p>In these cases, we can set up row-level security, which specifies which data can be accessed using the anon key.</p>
<p>To learn more about row-level security, read this <a target="_blank" href="https://supabase.io/docs/learn/auth-deep-dive/auth-row-level-security">documentation</a>.</p>
<p>Returning back to the application, once the project is configured you'll get the following message "<strong>Welcome to your new project</strong>."</p>
<h3 id="heading-how-to-create-tables-in-the-database">How to Create Tables in the Database</h3>
<p>Now let's create a script to create tables in our database.</p>
<p>Go to the SQL section from the sidebar and click on New query.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-17-at-12.59.51-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>SQL section from Supabase panel</em></p>
<p>Click on New Query and copy-paste the following code:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">profiles</span> (
  <span class="hljs-keyword">id</span> <span class="hljs-keyword">uuid</span> <span class="hljs-keyword">references</span> auth.users <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
  username <span class="hljs-built_in">text</span> <span class="hljs-keyword">unique</span>,
  avatarUrl <span class="hljs-built_in">text</span>,
  website <span class="hljs-built_in">text</span>,
  bio <span class="hljs-built_in">text</span>,
  joinedAt <span class="hljs-built_in">timestamp</span> <span class="hljs-keyword">with</span> <span class="hljs-built_in">time</span> zone <span class="hljs-keyword">default</span> timezone(<span class="hljs-string">'utc'</span>::<span class="hljs-built_in">text</span>, <span class="hljs-keyword">now</span>()) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,

  primary <span class="hljs-keyword">key</span> (<span class="hljs-keyword">id</span>),
  <span class="hljs-keyword">unique</span>(username)
);

<span class="hljs-keyword">alter</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">profiles</span> <span class="hljs-keyword">enable</span> <span class="hljs-keyword">row</span> <span class="hljs-keyword">level</span> <span class="hljs-keyword">security</span>;

<span class="hljs-keyword">create</span> <span class="hljs-keyword">policy</span> <span class="hljs-string">"Profiles are viewable by user only."</span>
  <span class="hljs-keyword">on</span> <span class="hljs-keyword">profiles</span> <span class="hljs-keyword">for</span> <span class="hljs-keyword">select</span>
  <span class="hljs-keyword">using</span> ( auth.uid() = <span class="hljs-keyword">id</span> );

<span class="hljs-keyword">create</span> <span class="hljs-keyword">policy</span> <span class="hljs-string">"Users can insert their own profile."</span>
  <span class="hljs-keyword">on</span> <span class="hljs-keyword">profiles</span> <span class="hljs-keyword">for</span> <span class="hljs-keyword">insert</span>
  <span class="hljs-keyword">with</span> <span class="hljs-keyword">check</span> ( auth.uid() = <span class="hljs-keyword">id</span> );

<span class="hljs-keyword">create</span> <span class="hljs-keyword">policy</span> <span class="hljs-string">"Users can update own profile."</span>
  <span class="hljs-keyword">on</span> <span class="hljs-keyword">profiles</span> <span class="hljs-keyword">for</span> <span class="hljs-keyword">update</span>
  <span class="hljs-keyword">using</span> ( auth.uid() = <span class="hljs-keyword">id</span> );

<span class="hljs-keyword">begin</span>;
  <span class="hljs-keyword">drop</span> publication <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> supabase_realtime;
  <span class="hljs-keyword">create</span> publication supabase_realtime;
<span class="hljs-keyword">commit</span>;
<span class="hljs-keyword">alter</span> publication supabase_realtime <span class="hljs-keyword">add</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">profiles</span>;

<span class="hljs-comment">-- Set up Storage!</span>
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> storage.buckets (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>)
<span class="hljs-keyword">values</span> (<span class="hljs-string">'avatars'</span>, <span class="hljs-string">'avatars'</span>);

<span class="hljs-keyword">create</span> <span class="hljs-keyword">policy</span> <span class="hljs-string">"Avatar images are publicly accessible."</span>
  <span class="hljs-keyword">on</span> storage.objects <span class="hljs-keyword">for</span> <span class="hljs-keyword">select</span>
  <span class="hljs-keyword">using</span> ( bucket_id = <span class="hljs-string">'avatars'</span>);

<span class="hljs-keyword">create</span> <span class="hljs-keyword">policy</span> <span class="hljs-string">"Anyone can upload an avatar."</span>
  <span class="hljs-keyword">on</span> storage.objects <span class="hljs-keyword">for</span> <span class="hljs-keyword">insert</span>
  <span class="hljs-keyword">with</span> <span class="hljs-keyword">check</span> ( bucket_id = <span class="hljs-string">'avatars'</span> );

<span class="hljs-keyword">create</span> <span class="hljs-keyword">policy</span> <span class="hljs-string">"Anyone can update an avatar."</span>
  <span class="hljs-keyword">on</span> storage.objects <span class="hljs-keyword">for</span> <span class="hljs-keyword">update</span>
  <span class="hljs-keyword">with</span> <span class="hljs-keyword">check</span> ( bucket_id = <span class="hljs-string">'avatars'</span> );
</code></pre>
<p>Let's understand this <strong>Profiles</strong> script piece by piece.</p>
<p>First, we create table profiles that relate to users in our TodoApp. To understand how to set up unique in a table, we have set up username as a unique constraint and primary key as id.</p>
<p>After that, we set up the row-level security and assign policies so that each individual can access only their data.</p>
<p>After that, we enable real-time for our database. Realtime gives an event whenever there are any changes in the row, and we can update the UI accordingly.</p>
<p>Now click on the <strong>RUN</strong> button at the right corner and you'll get the following message:</p>
<pre><code class="lang-shell">Success. No rows returned
</code></pre>
<p>Now let's create our todos table. For generating the table, click on the <strong>New query</strong> button and copy-paste the following script:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> todos (
  <span class="hljs-keyword">id</span> <span class="hljs-built_in">bigint</span> <span class="hljs-keyword">generated</span> <span class="hljs-keyword">by</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">as</span> <span class="hljs-keyword">identity</span> primary <span class="hljs-keyword">key</span>,
  user_id <span class="hljs-keyword">uuid</span> <span class="hljs-keyword">references</span> auth.users <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
  title <span class="hljs-built_in">text</span>,
  description <span class="hljs-built_in">text</span>,
  <span class="hljs-string">"isComplete"</span> <span class="hljs-built_in">boolean</span> <span class="hljs-keyword">default</span> <span class="hljs-literal">false</span>,
  insertedAt <span class="hljs-built_in">timestamp</span> <span class="hljs-keyword">with</span> <span class="hljs-built_in">time</span> zone <span class="hljs-keyword">default</span> timezone(<span class="hljs-string">'utc'</span>::<span class="hljs-built_in">text</span>, <span class="hljs-keyword">now</span>()) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>
);

<span class="hljs-keyword">alter</span> <span class="hljs-keyword">table</span> todos <span class="hljs-keyword">enable</span> <span class="hljs-keyword">row</span> <span class="hljs-keyword">level</span> <span class="hljs-keyword">security</span>;

<span class="hljs-keyword">create</span> <span class="hljs-keyword">policy</span> <span class="hljs-string">"Individuals can create todos."</span> <span class="hljs-keyword">on</span> todos <span class="hljs-keyword">for</span>
    <span class="hljs-keyword">insert</span> <span class="hljs-keyword">with</span> <span class="hljs-keyword">check</span> (auth.uid() = user_id);

<span class="hljs-keyword">create</span> <span class="hljs-keyword">policy</span> <span class="hljs-string">"Individuals can view their own todos. "</span> <span class="hljs-keyword">on</span> todos <span class="hljs-keyword">for</span>
    <span class="hljs-keyword">select</span> <span class="hljs-keyword">using</span> (auth.uid() = user_id);

<span class="hljs-keyword">create</span> <span class="hljs-keyword">policy</span> <span class="hljs-string">"Individuals can update their own todos."</span> <span class="hljs-keyword">on</span> todos <span class="hljs-keyword">for</span>
    <span class="hljs-keyword">update</span> <span class="hljs-keyword">using</span> (auth.uid() = user_id);

<span class="hljs-keyword">create</span> <span class="hljs-keyword">policy</span> <span class="hljs-string">"Individuals can delete their own todos."</span> <span class="hljs-keyword">on</span> todos <span class="hljs-keyword">for</span>
    <span class="hljs-keyword">delete</span> <span class="hljs-keyword">using</span> (auth.uid() = user_id);
</code></pre>
<p>Now click on the <strong>RUN</strong> button at the right corner, and you'll get the following message:</p>
<pre><code class="lang-shell">Success. No rows returned
</code></pre>
<p>To confirm our tables are generated, go to the table editor section from the sidebar.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-17-at-1.28.59-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Table Editor section from Supabase panel</em></p>
<p>Inside the table editor, you'll find our tables generated successfully.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-17-at-1.33.43-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Supabase Table sidebar</em></p>
<p>As you can see in the above Todos Script, we didn't enable real-time. To enable a real-time server, we need to go to the <strong>Database &gt; Replication</strong> section.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-17-at-1.36.33-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Database section from Supabase panel</em></p>
<p>Here you'll see the following view:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-17-at-1.38.08-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Supabase Database Replication Section</em></p>
<p>Click on the <strong>1 table</strong> button under source and then toggle the switch for todos. It will enable a real-time server for our todos also.</p>
<p>Now suppose we want to disable row-level security for todos <strong>(note that this is not advisable),</strong> but just for the scope of the article to understand how to, we will disable it.</p>
<p>Go to the Authentication section and, inside that, go to the Policies.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-17-at-1.41.50-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Authentication section from Supabase panel</em></p>
<p>Now you'll see the todos section with RLS enabled written in the green box. Click on the Disable RLS option at the top right-hand corner of this box. It will disable the row-level security for our application.</p>
<h2 id="heading-how-to-implement-sign-in-using-supabase">How to Implement Sign In Using Supabase</h2>
<p>The <strong>code</strong> for this section is available under this <strong>commit</strong> if you need to refer to it in the future for reference.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/Sharvin26/TodoApp-supabase/tree/b253c904f2f39ac80808620cf51c9584bfa90f4d">https://github.com/Sharvin26/TodoApp-supabase/tree/b253c904f2f39ac80808620cf51c9584bfa90f4d</a></div>
<p> </p>
<p>First, let's create our application using the following command:</p>
<pre><code class="lang-sh">npx create-next-app todo_app
</code></pre>
<p>It's time to install our dependencies and have a basic configuration in place.</p>
<h3 id="heading-how-to-install-chakra-ui">How to Install Chakra UI</h3>
<pre><code class="lang-sh">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-sh">npm i @chakra-ui/react @emotion/react@\^11 @emotion/styled@\^11 framer-motion@\^4
</code></pre>
<p>Now let's clean up our code by removing the code that is not required and configuring ChakraUI into our application.</p>
<p>As per Chakra's documentation, we need to wrap <code>&lt;Component /&gt;</code> with <code>ChakraProvider</code> in the <code>pages/_app.js</code>. Go to the <code>_app.js</code> and copy-paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { ChakraProvider, extendTheme } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
<span class="hljs-keyword">import</span> customTheme <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/theme"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyApp</span>(<span class="hljs-params">{ Component, pageProps }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ChakraProvider</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{customTheme}</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> MyApp;
</code></pre>
<p>Let's create a directory under our root directory and name it <strong>lib</strong>. Under this directory, create a file named <code>theme.js</code>.</p>
<p>Copy-paste the following code inside this file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { extendTheme } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>

<span class="hljs-keyword">const</span> config = {
  <span class="hljs-attr">initialColorMode</span>: <span class="hljs-string">"light"</span>,
  <span class="hljs-attr">useSystemColorMode</span>: <span class="hljs-literal">false</span>,
}

<span class="hljs-keyword">const</span> theme = extendTheme({ config })

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> theme
</code></pre>
<p>Now under the <strong>pages</strong> directory, create a <code>_document.js</code> file and copy-paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { ColorModeScript } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>
<span class="hljs-keyword">import</span> NextDocument, { Html, Head, Main, NextScript } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/document"</span>
<span class="hljs-keyword">import</span> theme <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/theme"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Document</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">NextDocument</span> </span>{
  render() {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Head</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
          {/* 👇 Here's the script */}
          <span class="hljs-tag">&lt;<span class="hljs-name">ColorModeScript</span> <span class="hljs-attr">initialColorMode</span>=<span class="hljs-string">{theme.config.initialColorMode}</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">NextScript</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Html</span>&gt;</span></span>
    )
  }
}
</code></pre>
<p>By creating <code>_document.js</code> and <code>theme.js</code> we have just set our color to be <strong>light</strong> by default.</p>
<p>From ChakraUI version <code>1.6.12</code>, it sets the system chosen color by default. So for some users who have dark mode enabled for the browser, the application will have a dark color theme. Dark mode is nice, but for starting purposes, we only want the color to be light.</p>
<p>Go to <code>index.js</code> and copy paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Box } <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">const</span> Home = <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>
      <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>TodoApp<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
          <span class="hljs-attr">content</span>=<span class="hljs-string">"Awesome todoapp to store your awesome todos"</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">Box</span>&gt;</span>Hello world<span class="hljs-tag">&lt;/<span class="hljs-name">Box</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">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<h3 id="heading-how-to-install-the-supabase-client-library">How to Install the Supabase Client Library</h3>
<pre><code class="lang-sh">npm i @supabase/supabase-js
</code></pre>
<p>Under <strong>lib</strong> directory create a file named <code>client.js</code>.</p>
<p>Under that file copy paste the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@supabase/supabase-js"</span>;

<span class="hljs-keyword">const</span> SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL;
<span class="hljs-keyword">const</span> SUPBASE_ANON_KEY = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;

<span class="hljs-keyword">const</span> client = createClient(SUPABASE_URL, SUPBASE_ANON_KEY);

<span class="hljs-keyword">export</span> { client <span class="hljs-keyword">as</span> supabaseClient };
</code></pre>
<p>Here we are just creating a <strong>Supabase Client</strong> which will be used throughout the project.</p>
<p>Now under the root directory create a <code>.env.local</code> file and copy-paste the following part with Supabase URL and anon key:</p>
<pre><code class="lang-shell">NEXT_PUBLIC_SUPABASE_URL=#Add_your_supabase_url 
NEXT_PUBLIC_SUPABASE_ANON_KEY=#Add_your_supabase_key
</code></pre>
<p>You can find the Supabase URL and anon key under the <strong>Settings &gt; API</strong> section.</p>
<p>Under Project API keys is the <strong>anon</strong> key and under Config is the <strong>URL</strong>.</p>
<p>With this, our Supabase client is configured and ready to use.</p>
<p>Let's run our application using the following command:</p>
<pre><code class="lang-shell">npm run dev
</code></pre>
<p>You'll get the following output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-04-at-10.03.31-PM-2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Todo App Home Screen</em></p>
<p>Now under the <strong>pages</strong> directory, create a file named <code>signin.js</code> and copy-paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> {
  Alert,
  AlertIcon,
  Box,
  Button,
  chakra,
  FormControl,
  FormLabel,
  Heading,
  Input,
  Stack,
  Text,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { supabaseClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/client"</span>;

<span class="hljs-keyword">const</span> SignIn = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [email, setEmail] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [isSubmitted, setIsSubmitted] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [error, setError] = useState(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">const</span> submitHandler = <span class="hljs-keyword">async</span> (event) =&gt; {
    event.preventDefault();
    setIsLoading(<span class="hljs-literal">true</span>);
    setError(<span class="hljs-literal">null</span>);
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabaseClient.auth.signIn({
        email,
      });
      <span class="hljs-keyword">if</span> (error) {
        setError(error.message);
      } <span class="hljs-keyword">else</span> {
        setIsSubmitted(<span class="hljs-literal">true</span>);
      }
    } <span class="hljs-keyword">catch</span> (error) {
      setError(error.message);
    } <span class="hljs-keyword">finally</span> {
      setIsLoading(<span class="hljs-literal">false</span>);
    }
  };

  <span class="hljs-keyword">const</span> changeHandler = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setEmail(event.target.value);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">minH</span>=<span class="hljs-string">"100vh"</span> <span class="hljs-attr">py</span>=<span class="hljs-string">"12"</span> <span class="hljs-attr">px</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">base:</span> "<span class="hljs-attr">4</span>", <span class="hljs-attr">lg:</span> "<span class="hljs-attr">8</span>" }} <span class="hljs-attr">bg</span>=<span class="hljs-string">"gray.50"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">maxW</span>=<span class="hljs-string">"md"</span> <span class="hljs-attr">mx</span>=<span class="hljs-string">"auto"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">textAlign</span>=<span class="hljs-string">"center"</span> <span class="hljs-attr">m</span>=<span class="hljs-string">"6"</span>&gt;</span>
          Welcome to Todo App
        <span class="hljs-tag">&lt;/<span class="hljs-name">Heading</span>&gt;</span>
        {error &amp;&amp; (
          <span class="hljs-tag">&lt;<span class="hljs-name">Alert</span> <span class="hljs-attr">status</span>=<span class="hljs-string">"error"</span> <span class="hljs-attr">mb</span>=<span class="hljs-string">"6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">AlertIcon</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Text</span> <span class="hljs-attr">textAlign</span>=<span class="hljs-string">"center"</span>&gt;</span>{error}<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Alert</span>&gt;</span>
        )}
        <span class="hljs-tag">&lt;<span class="hljs-name">Box</span>
          <span class="hljs-attr">py</span>=<span class="hljs-string">"8"</span>
          <span class="hljs-attr">px</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">10</span>" }}
          <span class="hljs-attr">shadow</span>=<span class="hljs-string">"base"</span>
          <span class="hljs-attr">rounded</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">sm:</span> "<span class="hljs-attr">lg</span>" }}
          <span class="hljs-attr">bg</span>=<span class="hljs-string">"white"</span>
        &gt;</span>
          {isSubmitted ? (
            <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"md"</span> <span class="hljs-attr">textAlign</span>=<span class="hljs-string">"center"</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"gray.600"</span>&gt;</span>
              Please check {email} for login link
            <span class="hljs-tag">&lt;/<span class="hljs-name">Heading</span>&gt;</span>
          ) : (
            <span class="hljs-tag">&lt;<span class="hljs-name">chakra.form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{submitHandler}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Stack</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">"6"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">FormControl</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span>&gt;</span>Email address<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">"email"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
                    <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"email"</span>
                    <span class="hljs-attr">required</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">{email}</span>
                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{changeHandler}</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">Button</span>
                  <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
                  <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"blue"</span>
                  <span class="hljs-attr">size</span>=<span class="hljs-string">"lg"</span>
                  <span class="hljs-attr">fontSize</span>=<span class="hljs-string">"md"</span>
                  <span class="hljs-attr">isLoading</span>=<span class="hljs-string">{isLoading}</span>
                &gt;</span>
                  Sign in
                <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">Stack</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">chakra.form</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">Box</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> SignIn;
</code></pre>
<p>Here we have created a form and used a <strong>supabase auth</strong> method to sign in the user.</p>
<blockquote>
<p><strong>Note:</strong> In <code>supabaseClient.auth.signIn</code> method, when you don't pass a password, it considers the authentication method as the <strong>magic link</strong>.</p>
</blockquote>
<p>Now go to the <code>_app.js</code> and copy paste 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> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/router"</span>;
<span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { supabaseClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/client"</span>;
<span class="hljs-keyword">import</span> customTheme <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/theme"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyApp</span>(<span class="hljs-params">{ Component, pageProps }</span>) </span>{
  <span class="hljs-keyword">const</span> router = useRouter();
  <span class="hljs-keyword">const</span> user = supabaseClient.auth.user();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: authListener } = supabaseClient.auth.onAuthStateChange(
      <span class="hljs-function">(<span class="hljs-params">event, session</span>) =&gt;</span> {
        handleAuthSession(event, session);
        <span class="hljs-keyword">if</span> (event === <span class="hljs-string">"SIGNED_IN"</span>) {
          <span class="hljs-keyword">const</span> signedInUser = supabaseClient.auth.user();
          <span class="hljs-keyword">const</span> userId = signedInUser.id;
          supabaseClient
            .from(<span class="hljs-string">"profiles"</span>)
            .upsert({ <span class="hljs-attr">id</span>: userId })
            .then(<span class="hljs-function">(<span class="hljs-params">_data, error</span>) =&gt;</span> {
              <span class="hljs-keyword">if</span> (!error) {
                router.push(<span class="hljs-string">"/"</span>);
              }
            });
        }
        <span class="hljs-keyword">if</span> (event === <span class="hljs-string">"SIGNED_OUT"</span>) {
          router.push(<span class="hljs-string">"/signin"</span>);
        }
      }
    );

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      authListener.unsubscribe();
    };
  }, [router]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (user) {
      <span class="hljs-keyword">if</span> (router.pathname === <span class="hljs-string">"/signin"</span>) {
        router.push(<span class="hljs-string">"/"</span>);
      }
    }
  }, [router.pathname, user, router]);

  <span class="hljs-keyword">const</span> handleAuthSession = <span class="hljs-keyword">async</span> (event, session) =&gt; {
    <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"/api/auth"</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
      <span class="hljs-attr">headers</span>: <span class="hljs-keyword">new</span> Headers({ <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> }),
      <span class="hljs-attr">credentials</span>: <span class="hljs-string">"same-origin"</span>,
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ event, session }),
    });
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ChakraProvider</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{customTheme}</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> MyApp;
</code></pre>
<p>Now inside the <strong>API</strong> directory, remove the <code>hello.js</code> file and create a new file called <code>auth.js</code>. Copy-paste the following code in that new file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { supabaseClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../lib/client"</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">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  supabaseClient.auth.api.setAuthCookie(req, res);
}
</code></pre>
<p>The code under <code>_app.js</code> is crucial for authentication when the user clicks on the magic link.</p>
<p>Supabase provides a listener method under the hood <code>auth.onAuthStateChange</code> which gives two events <code>SIGNED_IN</code> and <code>SIGNED_OUT</code>.</p>
<p>We use <code>SIGNED_IN</code> event to set a cookie by calling <code>/api/auth</code> which uses another method exposed by supabase. This method <code>auth.api.setAuthCookie</code> is useful to set cookies via server-side. Once the user is authenticated we push the user to the <code>/</code> page where all todos will be.</p>
<p>Now let's restart our server using <code>npm run dev</code> and then go to <code>http://localhost:3000/signin</code>. You'll see the following UI:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-04-at-10.50.26-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Todo SignIn Page</em></p>
<p>Add your email and click the submit button. Go to the email and click on verify, and you'll be redirected to the <code>/</code> page.</p>
<h2 id="heading-how-to-show-all-todos-add-new-todos-and-update-and-delete-todos">How to Show All Todos, Add New Todos, and Update and Delete Todos</h2>
<p>The <strong>code</strong> is available under this <strong>commit</strong> if you need to refer to it in the future for reference.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/Sharvin26/TodoApp-supabase/tree/c2d1361b461d301549a813fda350c69a3e23e579">https://github.com/Sharvin26/TodoApp-supabase/tree/c2d1361b461d301549a813fda350c69a3e23e579</a></div>
<p> </p>
<p>Before implementing Todo crud operations, let's implement the logout functionality. Go to <code>index.js</code> and replace the existing code 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">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/router"</span>;
<span class="hljs-keyword">import</span> { 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">"../components/Navbar"</span>;
<span class="hljs-keyword">import</span> { supabaseClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/client"</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> router = useRouter();
  <span class="hljs-keyword">const</span> user = supabaseClient.auth.user();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (!user) {
      router.push(<span class="hljs-string">"/signin"</span>);
    }
  }, [user, router]);

  <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>TodoApp<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
          <span class="hljs-attr">content</span>=<span class="hljs-string">"Awesome todoapp to store your awesome todos"</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">Navbar</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">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Create a <strong>component</strong> directory under the root directory, and inside the <strong>component</strong> directory create a file named <code>Navbar.js</code>. Copy-paste the following content under that file:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Box, Button, ButtonGroup, Flex, Heading } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
<span class="hljs-keyword">import</span> NavLink <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</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> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { supabaseClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/client"</span>;

<span class="hljs-keyword">const</span> Navbar = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> router = useRouter();
  <span class="hljs-keyword">const</span> [isLogoutLoading, setIsLogoutLoading] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> logoutHandler = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      setIsLogoutLoading(<span class="hljs-literal">true</span>);
      <span class="hljs-keyword">await</span> supabaseClient.auth.signOut();
      router.push(<span class="hljs-string">"/signin"</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      router.push(<span class="hljs-string">"/signin"</span>);
    } <span class="hljs-keyword">finally</span> {
      setIsLogoutLoading(<span class="hljs-literal">false</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">height</span>=<span class="hljs-string">"100%"</span> <span class="hljs-attr">p</span>=<span class="hljs-string">"5"</span> <span class="hljs-attr">bg</span>=<span class="hljs-string">"gray.100"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">maxW</span>=<span class="hljs-string">"6xl"</span> <span class="hljs-attr">mx</span>=<span class="hljs-string">"auto"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Flex</span>
          <span class="hljs-attr">as</span>=<span class="hljs-string">"nav"</span>
          <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Site navigation"</span>
          <span class="hljs-attr">align</span>=<span class="hljs-string">"center"</span>
          <span class="hljs-attr">justify</span>=<span class="hljs-string">"space-between"</span>
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">mr</span>=<span class="hljs-string">"4"</span>&gt;</span>TodoApp<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">NavLink</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/profile"</span>&gt;</span>Profile<span class="hljs-tag">&lt;/<span class="hljs-name">NavLink</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ButtonGroup</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">"4"</span> <span class="hljs-attr">ml</span>=<span class="hljs-string">"6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"blue"</span>&gt;</span>Add Todo<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
                <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"red"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{logoutHandler}</span>
                <span class="hljs-attr">isLoading</span>=<span class="hljs-string">{isLogoutLoading}</span>
              &gt;</span>
                Logout
              <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ButtonGroup</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">Box</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">default</span> Navbar;
</code></pre>
<p>We have created a navbar component with a Profile link, Add Todo button, and a Logout button.</p>
<p>The <code>logoutHandler</code> uses a Supabase method called <code>signOut</code> to clear the session and log us out of the application.</p>
<p>Go to http://localhost:3000 and click on the <strong>Logout</strong> button.</p>
<p>The cookie will be cleared from the browser, and the user will get redirected to <strong>the sign-in</strong> page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-05-at-11.54.09-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>TodoApp Home Page</em></p>
<h3 id="heading-how-to-add-a-todo">How to Add a Todo</h3>
<p>Go to the <code>Navbar.js</code> and copy paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Box, Button, ButtonGroup, Flex, Heading } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
<span class="hljs-keyword">import</span> NavLink <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</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> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { supabaseClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/client"</span>;

<span class="hljs-keyword">const</span> Navbar = <span class="hljs-function">(<span class="hljs-params">{ onOpen }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> router = useRouter();
  <span class="hljs-keyword">const</span> [isLogoutLoading, setIsLogoutLoading] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> logoutHandler = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      setIsLogoutLoading(<span class="hljs-literal">true</span>);
      <span class="hljs-keyword">await</span> supabaseClient.auth.signOut();
      router.push(<span class="hljs-string">"/signin"</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      router.push(<span class="hljs-string">"/signin"</span>);
    } <span class="hljs-keyword">finally</span> {
      setIsLogoutLoading(<span class="hljs-literal">false</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">height</span>=<span class="hljs-string">"100%"</span> <span class="hljs-attr">p</span>=<span class="hljs-string">"5"</span> <span class="hljs-attr">bg</span>=<span class="hljs-string">"gray.100"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">maxW</span>=<span class="hljs-string">"6xl"</span> <span class="hljs-attr">mx</span>=<span class="hljs-string">"auto"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Flex</span>
          <span class="hljs-attr">as</span>=<span class="hljs-string">"nav"</span>
          <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Site navigation"</span>
          <span class="hljs-attr">align</span>=<span class="hljs-string">"center"</span>
          <span class="hljs-attr">justify</span>=<span class="hljs-string">"space-between"</span>
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">mr</span>=<span class="hljs-string">"4"</span>&gt;</span>TodoApp<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">NavLink</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/profile"</span>&gt;</span>Profile<span class="hljs-tag">&lt;/<span class="hljs-name">NavLink</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ButtonGroup</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">"4"</span> <span class="hljs-attr">ml</span>=<span class="hljs-string">"6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"blue"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onOpen}</span>&gt;</span>
                Add Todo
              <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
                <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"red"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{logoutHandler}</span>
                <span class="hljs-attr">isLoading</span>=<span class="hljs-string">{isLogoutLoading}</span>
              &gt;</span>
                Logout
              <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ButtonGroup</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">Box</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">default</span> Navbar;
</code></pre>
<p>Here we have just assigned an onClick handler to our Add Todo button which will open a modal to add a todo.</p>
<p>Now create a file named <code>ManageTodo.js</code> under the <strong>components</strong> directory and copy paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> {
  Alert,
  AlertIcon,
  Button,
  ButtonGroup,
  FormControl,
  FormHelperText,
  FormLabel,
  Input,
  Modal,
  ModalBody,
  ModalCloseButton,
  ModalContent,
  ModalFooter,
  ModalHeader,
  ModalOverlay,
  Switch,
  Text,
  Textarea,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { supabaseClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/client"</span>;

<span class="hljs-keyword">const</span> ManageTodo = <span class="hljs-function">(<span class="hljs-params">{ isOpen, onClose, initialRef }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [description, setDescription] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [isComplete, setIsComplete] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [isLoading, setIsLoading] = 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> submitHandler = <span class="hljs-keyword">async</span> (event) =&gt; {
    event.preventDefault();
    setErrorMessage(<span class="hljs-string">""</span>);
    <span class="hljs-keyword">if</span> (description.length &lt;= <span class="hljs-number">10</span>) {
      setErrorMessage(<span class="hljs-string">"Description must have more than 10 characters"</span>);
      <span class="hljs-keyword">return</span>;
    }
    setIsLoading(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">const</span> user = supabaseClient.auth.user();
    <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabaseClient
      .from(<span class="hljs-string">"todos"</span>)
      .insert([{ title, description, isComplete, <span class="hljs-attr">user_id</span>: user.id }]);
    setIsLoading(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">if</span> (error) {
      setErrorMessage(error.message);
    } <span class="hljs-keyword">else</span> {
      closeHandler();
    }
  };

  <span class="hljs-keyword">const</span> closeHandler = <span class="hljs-function">() =&gt;</span> {
    setTitle(<span class="hljs-string">""</span>);
    setDescription(<span class="hljs-string">""</span>);
    setIsComplete(<span class="hljs-literal">false</span>);
    onClose();
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Modal</span>
      <span class="hljs-attr">isOpen</span>=<span class="hljs-string">{isOpen}</span>
      <span class="hljs-attr">onClose</span>=<span class="hljs-string">{onClose}</span>
      <span class="hljs-attr">isCentered</span>
      <span class="hljs-attr">initialFocusRef</span>=<span class="hljs-string">{initialRef}</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ModalOverlay</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ModalContent</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{submitHandler}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ModalHeader</span>&gt;</span>Add Todo<span class="hljs-tag">&lt;/<span class="hljs-name">ModalHeader</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ModalCloseButton</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ModalBody</span> <span class="hljs-attr">pb</span>=<span class="hljs-string">{6}</span>&gt;</span>
            {errorMessage &amp;&amp; (
              <span class="hljs-tag">&lt;<span class="hljs-name">Alert</span> <span class="hljs-attr">status</span>=<span class="hljs-string">"error"</span> <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"lg"</span> <span class="hljs-attr">mb</span>=<span class="hljs-string">"6"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">AlertIcon</span> /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Text</span> <span class="hljs-attr">textAlign</span>=<span class="hljs-string">"center"</span>&gt;</span>{errorMessage}<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">Alert</span>&gt;</span>
            )}
            <span class="hljs-tag">&lt;<span class="hljs-name">FormControl</span> <span class="hljs-attr">isRequired</span>=<span class="hljs-string">{true}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span>&gt;</span>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">ref</span>=<span class="hljs-string">{initialRef}</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Add your title here"</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setTitle(event.target.value)}
                value={title}
              /&gt;
            <span class="hljs-tag">&lt;/<span class="hljs-name">FormControl</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">FormControl</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{4}</span> <span class="hljs-attr">isRequired</span>=<span class="hljs-string">{true}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span>&gt;</span>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">placeholder</span>=<span class="hljs-string">"Add your description here"</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setDescription(event.target.value)}
                value={description}
              /&gt;
              <span class="hljs-tag">&lt;<span class="hljs-name">FormHelperText</span>&gt;</span>
                Description must have more than 10 characters.
              <span class="hljs-tag">&lt;/<span class="hljs-name">FormHelperText</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">FormControl</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{4}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span>&gt;</span>Is Completed?<span class="hljs-tag">&lt;/<span class="hljs-name">FormLabel</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Switch</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{isComplete}</span>
                <span class="hljs-attr">id</span>=<span class="hljs-string">"is-completed"</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setIsComplete(!isComplete)}
              /&gt;
            <span class="hljs-tag">&lt;/<span class="hljs-name">FormControl</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">ModalBody</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">ModalFooter</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ButtonGroup</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">"3"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{closeHandler}</span>
                <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"red"</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"reset"</span>
                <span class="hljs-attr">isDisabled</span>=<span class="hljs-string">{isLoading}</span>
              &gt;</span>
                Cancel
              <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"blue"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">isLoading</span>=<span class="hljs-string">{isLoading}</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">ButtonGroup</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">ModalFooter</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">ModalContent</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Modal</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ManageTodo;
</code></pre>
<p>This part will be responsible for adding and updating the todos. Here we have created a modal with a form and 3 form control elements.</p>
<p>Once the form is submited we call a supabase server with following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabaseClient
      .from(<span class="hljs-string">"todos"</span>)
      .insert([{ title, description, isComplete, <span class="hljs-attr">user_id</span>: user.id }]);
</code></pre>
<p>This just inserts a new todo inside our supabase table.</p>
<p>Now let's go to <strong>pages</strong> &gt; <code>index.js</code> file and copy paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { useDisclosure } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/hooks"</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> { useEffect, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ManageTodo <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/ManageTodo"</span>;
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Navbar"</span>;
<span class="hljs-keyword">import</span> { supabaseClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/client"</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> initialRef = useRef();
  <span class="hljs-keyword">const</span> { isOpen, onOpen, onClose } = useDisclosure();

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

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (!user) {
      router.push(<span class="hljs-string">"/signin"</span>);
    }
  }, [user, router]);

  <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>TodoApp<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
          <span class="hljs-attr">content</span>=<span class="hljs-string">"Awesome todoapp to store your awesome todos"</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">Navbar</span> <span class="hljs-attr">onOpen</span>=<span class="hljs-string">{onOpen}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ManageTodo</span> <span class="hljs-attr">isOpen</span>=<span class="hljs-string">{isOpen}</span> <span class="hljs-attr">onClose</span>=<span class="hljs-string">{onClose}</span> <span class="hljs-attr">initialRef</span>=<span class="hljs-string">{initialRef}</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">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Here we are using <code>useDisclosure</code> hook from Chakra to maintain the modal state. Besides that you'll see we have passed <code>onOpen</code> to the Navbar and added the <code>ManageTodo</code> component.</p>
<p>Now go to <code>http://localhost:3000</code> and click on <strong>Add Todo</strong> Button. You'll see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-06-at-7.24.27-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Add Todo Modal</em></p>
<p>Fill out the form, click save, and then go to the Supabase todos table. You'll find that a new todo has been added to our table.</p>
<blockquote>
<p><strong>Note:</strong> Supabase sometimes requires manual refresh when a new record is added.</p>
</blockquote>
<h3 id="heading-how-to-get-all-todos">How to Get All Todos</h3>
<p>So our todos are getting added successfully. Now let's work on getting all todos from a Supabase table.</p>
<p>Under the <strong>components</strong> directory, create a file named <code>SingleTodo.js</code> and copy paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Box, Divider, Heading, Text, Tag } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;

<span class="hljs-keyword">const</span> SingleTodo = <span class="hljs-function">(<span class="hljs-params">{ todo }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> getDateInMonthDayYear = <span class="hljs-function">(<span class="hljs-params">date</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> d = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(date);
    <span class="hljs-keyword">const</span> options = {
      <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>,
      <span class="hljs-attr">hour</span>: <span class="hljs-string">"numeric"</span>,
      <span class="hljs-attr">minute</span>: <span class="hljs-string">"numeric"</span>,
    };
    <span class="hljs-keyword">const</span> n = d.toLocaleDateString(<span class="hljs-string">"en-US"</span>, options);
    <span class="hljs-keyword">const</span> replase = n.replace(<span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">","</span>, <span class="hljs-string">"g"</span>), <span class="hljs-string">" "</span>);
    <span class="hljs-keyword">return</span> replase;
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Box</span>
      <span class="hljs-attr">position</span>=<span class="hljs-string">"relative"</span>
      <span class="hljs-attr">maxW</span>=<span class="hljs-string">"sm"</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">overflow</span>=<span class="hljs-string">"hidden"</span>
      <span class="hljs-attr">p</span>=<span class="hljs-string">"4"</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"md"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">"3"</span>&gt;</span>{todo.title}<span class="hljs-tag">&lt;/<span class="hljs-name">Heading</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Tag</span>
        <span class="hljs-attr">position</span>=<span class="hljs-string">"absolute"</span>
        <span class="hljs-attr">top</span>=<span class="hljs-string">"3"</span>
        <span class="hljs-attr">right</span>=<span class="hljs-string">"2"</span>
        <span class="hljs-attr">bg</span>=<span class="hljs-string">{todo.isComplete</span> ? "<span class="hljs-attr">green.500</span>" <span class="hljs-attr">:</span> "<span class="hljs-attr">yellow.400</span>"}
        <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"3xl"</span>
        <span class="hljs-attr">size</span>=<span class="hljs-string">"sm"</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.400"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">"1"</span> <span class="hljs-attr">fontSize</span>=<span class="hljs-string">"sm"</span>&gt;</span>
        {getDateInMonthDayYear(todo.insertedat)}
      <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">my</span>=<span class="hljs-string">"4"</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>]} <span class="hljs-attr">color</span>=<span class="hljs-string">"gray.800"</span>&gt;</span>
        {todo.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">export</span> <span class="hljs-keyword">default</span> SingleTodo;
</code></pre>
<p>This is just UI code with a utitlity function converting the date to human readable format.</p>
<p>Go to the <code>index.js</code> and replace the old code with following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { useDisclosure } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/hooks"</span>;
<span class="hljs-keyword">import</span> { Box, SimpleGrid, Text, HStack, Tag } <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> { useEffect, useRef, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ManageTodo <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/ManageTodo"</span>;
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Navbar"</span>;
<span class="hljs-keyword">import</span> SingleTodo <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/SingleTodo"</span>;
<span class="hljs-keyword">import</span> { supabaseClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/client"</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> initialRef = useRef();
  <span class="hljs-keyword">const</span> [todos, setTodos] = useState([]);

  <span class="hljs-keyword">const</span> router = useRouter();
  <span class="hljs-keyword">const</span> { isOpen, onOpen, onClose } = useDisclosure();
  <span class="hljs-keyword">const</span> user = supabaseClient.auth.user();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (!user) {
      router.push(<span class="hljs-string">"/signin"</span>);
    }
  }, [user, router]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (user) {
      supabaseClient
        .from(<span class="hljs-string">"todos"</span>)
        .select(<span class="hljs-string">"*"</span>)
        .eq(<span class="hljs-string">"user_id"</span>, user?.id)
        .order(<span class="hljs-string">"id"</span>, { <span class="hljs-attr">ascending</span>: <span class="hljs-literal">false</span> })
        .then(<span class="hljs-function">(<span class="hljs-params">{ data, error }</span>) =&gt;</span> {
          <span class="hljs-keyword">if</span> (!error) {
            setTodos(data);
          }
        });
    }
  }, [user]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> todoListener = supabaseClient
      .from(<span class="hljs-string">"todos"</span>)
      .on(<span class="hljs-string">"*"</span>, <span class="hljs-function">(<span class="hljs-params">payload</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> newTodo = payload.new;
        setTodos(<span class="hljs-function">(<span class="hljs-params">oldTodos</span>) =&gt;</span> {
          <span class="hljs-keyword">const</span> newTodos = [...oldTodos, newTodo];
          newTodos.sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> b.id - a.id);
          <span class="hljs-keyword">return</span> newTodos;
        });
      })
      .subscribe();

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      todoListener.unsubscribe();
    };
  }, []);

  <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>TodoApp<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
          <span class="hljs-attr">content</span>=<span class="hljs-string">"Awesome todoapp to store your awesome todos"</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">Navbar</span> <span class="hljs-attr">onOpen</span>=<span class="hljs-string">{onOpen}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ManageTodo</span> <span class="hljs-attr">isOpen</span>=<span class="hljs-string">{isOpen}</span> <span class="hljs-attr">onClose</span>=<span class="hljs-string">{onClose}</span> <span class="hljs-attr">initialRef</span>=<span class="hljs-string">{initialRef}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">HStack</span> <span class="hljs-attr">m</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">"4"</span> <span class="hljs-attr">justify</span>=<span class="hljs-string">"center"</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">Tag</span> <span class="hljs-attr">bg</span>=<span class="hljs-string">"green.500"</span> <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"3xl"</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"sm"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">"1"</span> /&gt;</span> Complete
          <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">Tag</span> <span class="hljs-attr">bg</span>=<span class="hljs-string">"yellow.400"</span> <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"3xl"</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"sm"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">"1"</span> /&gt;</span>{" "}
            Incomplete
          <span class="hljs-tag">&lt;/<span class="hljs-name">Box</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>
          <span class="hljs-attr">columns</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">base:</span> <span class="hljs-attr">2</span>, <span class="hljs-attr">md:</span> <span class="hljs-attr">3</span>, <span class="hljs-attr">lg:</span> <span class="hljs-attr">4</span> }}
          <span class="hljs-attr">gap</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">6</span>", <span class="hljs-attr">lg:</span> "<span class="hljs-attr">8</span>" }}
          <span class="hljs-attr">m</span>=<span class="hljs-string">"10"</span>
        &gt;</span>
          {todos.map((todo) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">SingleTodo</span> <span class="hljs-attr">todo</span>=<span class="hljs-string">{todo}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{todo.id}</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">main</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> Home;
</code></pre>
<p>Let's understand the code. Here we have added two useEffects:</p>
<pre><code class="lang-js">  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (user) {
      supabaseClient
        .from(<span class="hljs-string">"todos"</span>)
        .select(<span class="hljs-string">"*"</span>)
        .eq(<span class="hljs-string">"user_id"</span>, user?.id)
        .order(<span class="hljs-string">"id"</span>, { <span class="hljs-attr">ascending</span>: <span class="hljs-literal">false</span> })
        .then(<span class="hljs-function">(<span class="hljs-params">{ data, error }</span>) =&gt;</span> {
          <span class="hljs-keyword">if</span> (!error) {
            setTodos(data);
          }
        });
    }
  }, [user]);
</code></pre>
<p>This useEffect is usefull when the page is rendered for the first time. We query data from the Supabase table for that particular user in descending fashion.</p>
<pre><code class="lang-js">  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> todoListener = supabaseClient
      .from(<span class="hljs-string">"todos"</span>)
      .on(<span class="hljs-string">"*"</span>, <span class="hljs-function">(<span class="hljs-params">payload</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> newTodo = payload.new;
        setTodos(<span class="hljs-function">(<span class="hljs-params">oldTodos</span>) =&gt;</span> {
          <span class="hljs-keyword">const</span> newTodos = [...oldTodos, newTodo];
          newTodos.sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> b.id - a.id);
          <span class="hljs-keyword">return</span> newTodos;
        });
      })
      .subscribe();

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      todoListener.unsubscribe();
    };
  }, []);
</code></pre>
<p>This useEffect is a real time subscription with the Supabase real time server. Whenever a new todo is added we get the payload event which we use to add the todo in our local state.</p>
<blockquote>
<p><strong>Note:</strong> the Supabase docs suggest not using real time subscription on a server-side application.</p>
</blockquote>
<p>Now go to <code>http://localhost:3000</code> and add a todo. You'll see the following view:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-06-at-8.09.06-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>All Todos</em></p>
<h3 id="heading-how-to-update-a-todo">How to Update a Todo</h3>
<p>Updating the todo mechanism might be complex for beginners. So I'll explain the process as simply as I can:</p>
<ol>
<li><p>We create a <code>todo</code> state in our parent component of <code>index.js</code>. This todo state is updated when user clicks on SingleTodo.</p>
</li>
<li><p>We pass an <code>openHandler</code> function for doing that. This function updates the todo state with the clicked todo detail and opens the modal.</p>
</li>
<li><p>In <code>ManageTodo.js</code> we have written a <code>useEffect</code> with a dependency of <code>todo</code> which updates the values of <code>title</code>, <code>description</code>, and <code>isComplete</code> whenever the <code>todo</code> changes.</p>
</li>
<li><p>At last we update the todo in our table using the Supbase update method on the basis of <code>todo id</code>.</p>
</li>
</ol>
<p>Time to implement the code. Under the components directory, go to <code>SingleTodo.js</code> and replace the code with the following:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Box, Divider, Heading, Tag, Text } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;

<span class="hljs-keyword">const</span> SingleTodo = <span class="hljs-function">(<span class="hljs-params">{ todo, openHandler }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> getDateInMonthDayYear = <span class="hljs-function">(<span class="hljs-params">date</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> d = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(date);
    <span class="hljs-keyword">const</span> options = {
      <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>,
      <span class="hljs-attr">hour</span>: <span class="hljs-string">"numeric"</span>,
      <span class="hljs-attr">minute</span>: <span class="hljs-string">"numeric"</span>,
    };
    <span class="hljs-keyword">const</span> n = d.toLocaleDateString(<span class="hljs-string">"en-US"</span>, options);
    <span class="hljs-keyword">const</span> replase = n.replace(<span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">","</span>, <span class="hljs-string">"g"</span>), <span class="hljs-string">" "</span>);
    <span class="hljs-keyword">return</span> replase;
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Box</span>
      <span class="hljs-attr">position</span>=<span class="hljs-string">"relative"</span>
      <span class="hljs-attr">maxW</span>=<span class="hljs-string">"sm"</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">overflow</span>=<span class="hljs-string">"hidden"</span>
      <span class="hljs-attr">p</span>=<span class="hljs-string">"4"</span>
      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> openHandler(todo)}
    &gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"md"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">"3"</span>&gt;</span>
        {todo.title}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Heading</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Tag</span>
        <span class="hljs-attr">position</span>=<span class="hljs-string">"absolute"</span>
        <span class="hljs-attr">top</span>=<span class="hljs-string">"3"</span>
        <span class="hljs-attr">right</span>=<span class="hljs-string">"2"</span>
        <span class="hljs-attr">bg</span>=<span class="hljs-string">{todo.isComplete</span> ? "<span class="hljs-attr">green.500</span>" <span class="hljs-attr">:</span> "<span class="hljs-attr">yellow.400</span>"}
        <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"3xl"</span>
        <span class="hljs-attr">size</span>=<span class="hljs-string">"sm"</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.400"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">"1"</span> <span class="hljs-attr">fontSize</span>=<span class="hljs-string">"sm"</span>&gt;</span>
        {getDateInMonthDayYear(todo.insertedat)}
      <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">my</span>=<span class="hljs-string">"4"</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>]} <span class="hljs-attr">color</span>=<span class="hljs-string">"gray.800"</span>&gt;</span>
        {todo.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">export</span> <span class="hljs-keyword">default</span> SingleTodo;
</code></pre>
<p>Under the <strong>components</strong> directory go to <code>ManageTodo.js</code> and replace the code with the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> {
  Alert,
  AlertIcon,
  Button,
  ButtonGroup,
  FormControl,
  FormHelperText,
  FormLabel,
  Input,
  Modal,
  ModalBody,
  ModalCloseButton,
  ModalContent,
  ModalFooter,
  ModalHeader,
  ModalOverlay,
  Switch,
  Text,
  Textarea,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
<span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { supabaseClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/client"</span>;

<span class="hljs-keyword">const</span> ManageTodo = <span class="hljs-function">(<span class="hljs-params">{ isOpen, onClose, initialRef, todo, setTodo }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [description, setDescription] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [isComplete, setIsComplete] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [errorMessage, setErrorMessage] = useState(<span class="hljs-string">""</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (todo) {
      setTitle(todo.title);
      setDescription(todo.description);
      setIsComplete(todo.isComplete);
    }
  }, [todo]);

  <span class="hljs-keyword">const</span> submitHandler = <span class="hljs-keyword">async</span> (event) =&gt; {
    event.preventDefault();
    setErrorMessage(<span class="hljs-string">""</span>);
    <span class="hljs-keyword">if</span> (description.length &lt;= <span class="hljs-number">10</span>) {
      setErrorMessage(<span class="hljs-string">"Description must have more than 10 characters"</span>);
      <span class="hljs-keyword">return</span>;
    }
    setIsLoading(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">const</span> user = supabaseClient.auth.user();
    <span class="hljs-keyword">let</span> supabaseError;
    <span class="hljs-keyword">if</span> (todo) {
      <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabaseClient
        .from(<span class="hljs-string">"todos"</span>)
        .update({ title, description, isComplete, <span class="hljs-attr">user_id</span>: user.id })
        .eq(<span class="hljs-string">"id"</span>, todo.id);
      supabaseError = error;
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabaseClient
        .from(<span class="hljs-string">"todos"</span>)
        .insert([{ title, description, isComplete, <span class="hljs-attr">user_id</span>: user.id }]);
      supabaseError = error;
    }

    setIsLoading(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">if</span> (supabaseError) {
      setErrorMessage(supabaseError.message);
    } <span class="hljs-keyword">else</span> {
      closeHandler();
    }
  };

  <span class="hljs-keyword">const</span> closeHandler = <span class="hljs-function">() =&gt;</span> {
    setTitle(<span class="hljs-string">""</span>);
    setDescription(<span class="hljs-string">""</span>);
    setIsComplete(<span class="hljs-literal">false</span>);
    setTodo(<span class="hljs-literal">null</span>);
    onClose();
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Modal</span>
      <span class="hljs-attr">isOpen</span>=<span class="hljs-string">{isOpen}</span>
      <span class="hljs-attr">onClose</span>=<span class="hljs-string">{onClose}</span>
      <span class="hljs-attr">isCentered</span>
      <span class="hljs-attr">initialFocusRef</span>=<span class="hljs-string">{initialRef}</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ModalOverlay</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ModalContent</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{submitHandler}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ModalHeader</span>&gt;</span>{todo ? "Update Todo" : "Add Todo"}<span class="hljs-tag">&lt;/<span class="hljs-name">ModalHeader</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ModalCloseButton</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{closeHandler}</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ModalBody</span> <span class="hljs-attr">pb</span>=<span class="hljs-string">{6}</span>&gt;</span>
            {errorMessage &amp;&amp; (
              <span class="hljs-tag">&lt;<span class="hljs-name">Alert</span> <span class="hljs-attr">status</span>=<span class="hljs-string">"error"</span> <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"lg"</span> <span class="hljs-attr">mb</span>=<span class="hljs-string">"6"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">AlertIcon</span> /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Text</span> <span class="hljs-attr">textAlign</span>=<span class="hljs-string">"center"</span>&gt;</span>{errorMessage}<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">Alert</span>&gt;</span>
            )}
            <span class="hljs-tag">&lt;<span class="hljs-name">FormControl</span> <span class="hljs-attr">isRequired</span>=<span class="hljs-string">{true}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span>&gt;</span>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">ref</span>=<span class="hljs-string">{initialRef}</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Add your title here"</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setTitle(event.target.value)}
                value={title}
              /&gt;
            <span class="hljs-tag">&lt;/<span class="hljs-name">FormControl</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">FormControl</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{4}</span> <span class="hljs-attr">isRequired</span>=<span class="hljs-string">{true}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span>&gt;</span>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">placeholder</span>=<span class="hljs-string">"Add your description here"</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setDescription(event.target.value)}
                value={description}
              /&gt;
              <span class="hljs-tag">&lt;<span class="hljs-name">FormHelperText</span>&gt;</span>
                Description must have more than 10 characters.
              <span class="hljs-tag">&lt;/<span class="hljs-name">FormHelperText</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">FormControl</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">{4}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span>&gt;</span>Is Completed?<span class="hljs-tag">&lt;/<span class="hljs-name">FormLabel</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Switch</span>
                <span class="hljs-attr">isChecked</span>=<span class="hljs-string">{isComplete}</span>
                <span class="hljs-attr">id</span>=<span class="hljs-string">"is-completed"</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setIsComplete(!isComplete)}
              /&gt;
            <span class="hljs-tag">&lt;/<span class="hljs-name">FormControl</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">ModalBody</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">ModalFooter</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ButtonGroup</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">"3"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{closeHandler}</span>
                <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"red"</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"reset"</span>
                <span class="hljs-attr">isDisabled</span>=<span class="hljs-string">{isLoading}</span>
              &gt;</span>
                Cancel
              <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"blue"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">isLoading</span>=<span class="hljs-string">{isLoading}</span>&gt;</span>
                {todo ? "Update" : "Save"}
              <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ButtonGroup</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">ModalFooter</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">ModalContent</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Modal</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ManageTodo;
</code></pre>
<p>Let's understand the code above. Here we are checking if the user has clicked on the update button ( By checking if todo exists ) and then showing the data in the initial object.</p>
<p>Based upon the condition, showing update text instead of Save text on the button. Also, based upon condition, we execute supabase update if todo exists and if not then insert.</p>
<p>Go to <strong>pages &gt; index.js</strong> and replace the existing code with the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { useDisclosure } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/hooks"</span>;
<span class="hljs-keyword">import</span> { Box, HStack, SimpleGrid, Tag } <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> { useEffect, useRef, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ManageTodo <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/ManageTodo"</span>;
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Navbar"</span>;
<span class="hljs-keyword">import</span> SingleTodo <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/SingleTodo"</span>;
<span class="hljs-keyword">import</span> { supabaseClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/client"</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> initialRef = useRef();
  <span class="hljs-keyword">const</span> [todos, setTodos] = useState([]);
  <span class="hljs-keyword">const</span> [todo, setTodo] = useState(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">const</span> router = useRouter();
  <span class="hljs-keyword">const</span> { isOpen, onOpen, onClose } = useDisclosure();
  <span class="hljs-keyword">const</span> user = supabaseClient.auth.user();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (!user) {
      router.push(<span class="hljs-string">"/signin"</span>);
    }
  }, [user, router]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (user) {
      supabaseClient
        .from(<span class="hljs-string">"todos"</span>)
        .select(<span class="hljs-string">"*"</span>)
        .eq(<span class="hljs-string">"user_id"</span>, user?.id)
        .order(<span class="hljs-string">"id"</span>, { <span class="hljs-attr">ascending</span>: <span class="hljs-literal">false</span> })
        .then(<span class="hljs-function">(<span class="hljs-params">{ data, error }</span>) =&gt;</span> {
          <span class="hljs-keyword">if</span> (!error) {
            setTodos(data);
          }
        });
    }
  }, [user]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> todoListener = supabaseClient
      .from(<span class="hljs-string">"todos"</span>)
      .on(<span class="hljs-string">"*"</span>, <span class="hljs-function">(<span class="hljs-params">payload</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> newTodo = payload.new;
        setTodos(<span class="hljs-function">(<span class="hljs-params">oldTodos</span>) =&gt;</span> {
          <span class="hljs-keyword">const</span> exists = oldTodos.find(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> todo.id === newTodo.id);
          <span class="hljs-keyword">let</span> newTodos;
          <span class="hljs-keyword">if</span> (exists) {
            <span class="hljs-keyword">const</span> oldTodoIndex = oldTodos.findIndex(
              <span class="hljs-function">(<span class="hljs-params">obj</span>) =&gt;</span> obj.id === newTodo.id
            );
            oldTodos[oldTodoIndex] = newTodo;
            newTodos = oldTodos;
          } <span class="hljs-keyword">else</span> {
            newTodos = [...oldTodos, newTodo];
          }
          newTodos.sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> b.id - a.id);
          <span class="hljs-keyword">return</span> newTodos;
        });
      })
      .subscribe();

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      todoListener.unsubscribe();
    };
  }, []);

  <span class="hljs-keyword">const</span> openHandler = <span class="hljs-function">(<span class="hljs-params">clickedTodo</span>) =&gt;</span> {
    setTodo(clickedTodo);
    onOpen();
  };

  <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>TodoApp<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
          <span class="hljs-attr">content</span>=<span class="hljs-string">"Awesome todoapp to store your awesome todos"</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">Navbar</span> <span class="hljs-attr">onOpen</span>=<span class="hljs-string">{onOpen}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ManageTodo</span>
          <span class="hljs-attr">isOpen</span>=<span class="hljs-string">{isOpen}</span>
          <span class="hljs-attr">onClose</span>=<span class="hljs-string">{onClose}</span>
          <span class="hljs-attr">initialRef</span>=<span class="hljs-string">{initialRef}</span>
          <span class="hljs-attr">todo</span>=<span class="hljs-string">{todo}</span>
          <span class="hljs-attr">setTodo</span>=<span class="hljs-string">{setTodo}</span>
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">HStack</span> <span class="hljs-attr">m</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">"4"</span> <span class="hljs-attr">justify</span>=<span class="hljs-string">"center"</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">Tag</span> <span class="hljs-attr">bg</span>=<span class="hljs-string">"green.500"</span> <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"3xl"</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"sm"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">"1"</span> /&gt;</span> Complete
          <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">Tag</span> <span class="hljs-attr">bg</span>=<span class="hljs-string">"yellow.400"</span> <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"3xl"</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"sm"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">"1"</span> /&gt;</span>{" "}
            Incomplete
          <span class="hljs-tag">&lt;/<span class="hljs-name">Box</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>
          <span class="hljs-attr">columns</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">base:</span> <span class="hljs-attr">2</span>, <span class="hljs-attr">md:</span> <span class="hljs-attr">3</span>, <span class="hljs-attr">lg:</span> <span class="hljs-attr">4</span> }}
          <span class="hljs-attr">gap</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">6</span>", <span class="hljs-attr">lg:</span> "<span class="hljs-attr">8</span>" }}
          <span class="hljs-attr">m</span>=<span class="hljs-string">"10"</span>
        &gt;</span>
          {todos.map((todo) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">SingleTodo</span> <span class="hljs-attr">todo</span>=<span class="hljs-string">{todo}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{todo.id}</span> <span class="hljs-attr">openHandler</span>=<span class="hljs-string">{openHandler}</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">main</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> Home;
</code></pre>
<p>Here we add the <code>ManageTodo</code> component that we created and pass props that are used by this component.</p>
<p>Now go to <code>http://localhost:3000</code> and click on any todo to update it and you'll see the following view:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-06-at-8.10.10-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Update Todo</em></p>
<h3 id="heading-how-to-delete-a-todo">How to Delete a Todo</h3>
<p>This functionality will need us to update our some of existing code. First we will do that and then understand how it works and why changes are required.</p>
<p>Go to the <code>SingleTodo.js</code> inside the <strong>components</strong> directory and replace the existing code with the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> {
  Box,
  Divider,
  Heading,
  Tag,
  Text,
  Button,
  Center,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;

<span class="hljs-keyword">const</span> SingleTodo = <span class="hljs-function">(<span class="hljs-params">{ todo, openHandler, deleteHandler, isDeleteLoading }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> getDateInMonthDayYear = <span class="hljs-function">(<span class="hljs-params">date</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> d = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(date);
    <span class="hljs-keyword">const</span> options = {
      <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>,
      <span class="hljs-attr">hour</span>: <span class="hljs-string">"numeric"</span>,
      <span class="hljs-attr">minute</span>: <span class="hljs-string">"numeric"</span>,
    };
    <span class="hljs-keyword">const</span> n = d.toLocaleDateString(<span class="hljs-string">"en-US"</span>, options);
    <span class="hljs-keyword">const</span> replase = n.replace(<span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">","</span>, <span class="hljs-string">"g"</span>), <span class="hljs-string">" "</span>);
    <span class="hljs-keyword">return</span> replase;
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Box</span>
      <span class="hljs-attr">position</span>=<span class="hljs-string">"relative"</span>
      <span class="hljs-attr">maxW</span>=<span class="hljs-string">"sm"</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">overflow</span>=<span class="hljs-string">"hidden"</span>
      <span class="hljs-attr">p</span>=<span class="hljs-string">"4"</span>
      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> openHandler(todo)}
    &gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"md"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">"3"</span>&gt;</span>
        {todo.title}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Heading</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Tag</span>
        <span class="hljs-attr">position</span>=<span class="hljs-string">"absolute"</span>
        <span class="hljs-attr">top</span>=<span class="hljs-string">"3"</span>
        <span class="hljs-attr">right</span>=<span class="hljs-string">"2"</span>
        <span class="hljs-attr">bg</span>=<span class="hljs-string">{todo.isComplete</span> ? "<span class="hljs-attr">green.500</span>" <span class="hljs-attr">:</span> "<span class="hljs-attr">yellow.400</span>"}
        <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"3xl"</span>
        <span class="hljs-attr">size</span>=<span class="hljs-string">"sm"</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.400"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">"1"</span> <span class="hljs-attr">fontSize</span>=<span class="hljs-string">"sm"</span>&gt;</span>
        {getDateInMonthDayYear(todo.insertedat)}
      <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">my</span>=<span class="hljs-string">"4"</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>]} <span class="hljs-attr">color</span>=<span class="hljs-string">"gray.800"</span>&gt;</span>
        {todo.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">Button</span>
          <span class="hljs-attr">mt</span>=<span class="hljs-string">"4"</span>
          <span class="hljs-attr">size</span>=<span class="hljs-string">"sm"</span>
          <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"red"</span>
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{(event)</span> =&gt;</span> {
            event.stopPropagation();
            deleteHandler(todo.id);
          }}
          isDisabled={isDeleteLoading}
        &gt;
          Delete
        <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">Box</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> SingleTodo;
</code></pre>
<p>Here we have added a delete button with an onClick event. Now this delete event is under another event which opens the modal. So whenever we click on delete it will open the modal too.</p>
<p>We don't want this behavour, so we use a method from <code>event</code> called <code>stopPropagation</code>. This method doesn't allow events from children to be passed to the parent.</p>
<p>Now go to the <code>index.js</code> inside the <strong>pages</strong> directory and replace the existing code with the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useDisclosure } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/hooks"</span>;
<span class="hljs-keyword">import</span> { Box, HStack, SimpleGrid, Tag } <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> { useEffect, useRef, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ManageTodo <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/ManageTodo"</span>;
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Navbar"</span>;
<span class="hljs-keyword">import</span> SingleTodo <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/SingleTodo"</span>;
<span class="hljs-keyword">import</span> { supabaseClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/client"</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> initialRef = useRef();
  <span class="hljs-keyword">const</span> [todos, setTodos] = useState([]);
  <span class="hljs-keyword">const</span> [todo, setTodo] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [isDeleteLoading, setIsDeleteLoading] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> router = useRouter();
  <span class="hljs-keyword">const</span> { isOpen, onOpen, onClose } = useDisclosure();
  <span class="hljs-keyword">const</span> user = supabaseClient.auth.user();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (!user) {
      router.push(<span class="hljs-string">"/signin"</span>);
    }
  }, [user, router]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (user) {
      supabaseClient
        .from(<span class="hljs-string">"todos"</span>)
        .select(<span class="hljs-string">"*"</span>)
        .eq(<span class="hljs-string">"user_id"</span>, user?.id)
        .order(<span class="hljs-string">"id"</span>, { <span class="hljs-attr">ascending</span>: <span class="hljs-literal">false</span> })
        .then(<span class="hljs-function">(<span class="hljs-params">{ data, error }</span>) =&gt;</span> {
          <span class="hljs-keyword">if</span> (!error) {
            setTodos(data);
          }
        });
    }
  }, [user]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> todoListener = supabaseClient
      .from(<span class="hljs-string">"todos"</span>)
      .on(<span class="hljs-string">"*"</span>, <span class="hljs-function">(<span class="hljs-params">payload</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (payload.eventType !== <span class="hljs-string">"DELETE"</span>) {
          <span class="hljs-keyword">const</span> newTodo = payload.new;
          setTodos(<span class="hljs-function">(<span class="hljs-params">oldTodos</span>) =&gt;</span> {
            <span class="hljs-keyword">const</span> exists = oldTodos.find(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> todo.id === newTodo.id);
            <span class="hljs-keyword">let</span> newTodos;
            <span class="hljs-keyword">if</span> (exists) {
              <span class="hljs-keyword">const</span> oldTodoIndex = oldTodos.findIndex(
                <span class="hljs-function">(<span class="hljs-params">obj</span>) =&gt;</span> obj.id === newTodo.id
              );
              oldTodos[oldTodoIndex] = newTodo;
              newTodos = oldTodos;
            } <span class="hljs-keyword">else</span> {
              newTodos = [...oldTodos, newTodo];
            }
            newTodos.sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> b.id - a.id);
            <span class="hljs-keyword">return</span> newTodos;
          });
        }
      })
      .subscribe();

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      todoListener.unsubscribe();
    };
  }, []);

  <span class="hljs-keyword">const</span> openHandler = <span class="hljs-function">(<span class="hljs-params">clickedTodo</span>) =&gt;</span> {
    setTodo(clickedTodo);
    onOpen();
  };

  <span class="hljs-keyword">const</span> deleteHandler = <span class="hljs-keyword">async</span> (todoId) =&gt; {
    setIsDeleteLoading(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabaseClient
      .from(<span class="hljs-string">"todos"</span>)
      .delete()
      .eq(<span class="hljs-string">"id"</span>, todoId);
    <span class="hljs-keyword">if</span> (!error) {
      setTodos(todos.filter(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> todo.id !== todoId));
    }
    setIsDeleteLoading(<span class="hljs-literal">false</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>TodoApp<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
          <span class="hljs-attr">content</span>=<span class="hljs-string">"Awesome todoapp to store your awesome todos"</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">Navbar</span> <span class="hljs-attr">onOpen</span>=<span class="hljs-string">{onOpen}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ManageTodo</span>
          <span class="hljs-attr">isOpen</span>=<span class="hljs-string">{isOpen}</span>
          <span class="hljs-attr">onClose</span>=<span class="hljs-string">{onClose}</span>
          <span class="hljs-attr">initialRef</span>=<span class="hljs-string">{initialRef}</span>
          <span class="hljs-attr">todo</span>=<span class="hljs-string">{todo}</span>
          <span class="hljs-attr">setTodo</span>=<span class="hljs-string">{setTodo}</span>
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">HStack</span> <span class="hljs-attr">m</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">"4"</span> <span class="hljs-attr">justify</span>=<span class="hljs-string">"center"</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">Tag</span> <span class="hljs-attr">bg</span>=<span class="hljs-string">"green.500"</span> <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"3xl"</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"sm"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">"1"</span> /&gt;</span> Complete
          <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">Tag</span> <span class="hljs-attr">bg</span>=<span class="hljs-string">"yellow.400"</span> <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"3xl"</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"sm"</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">"1"</span> /&gt;</span>{" "}
            Incomplete
          <span class="hljs-tag">&lt;/<span class="hljs-name">Box</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>
          <span class="hljs-attr">columns</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">base:</span> <span class="hljs-attr">2</span>, <span class="hljs-attr">md:</span> <span class="hljs-attr">3</span>, <span class="hljs-attr">lg:</span> <span class="hljs-attr">4</span> }}
          <span class="hljs-attr">gap</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">6</span>", <span class="hljs-attr">lg:</span> "<span class="hljs-attr">8</span>" }}
          <span class="hljs-attr">m</span>=<span class="hljs-string">"10"</span>
        &gt;</span>
          {todos.map((todo, index) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">SingleTodo</span>
              <span class="hljs-attr">todo</span>=<span class="hljs-string">{todo}</span>
              <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>
              <span class="hljs-attr">openHandler</span>=<span class="hljs-string">{openHandler}</span>
              <span class="hljs-attr">deleteHandler</span>=<span class="hljs-string">{deleteHandler}</span>
              <span class="hljs-attr">isDeleteLoading</span>=<span class="hljs-string">{isDeleteLoading}</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">main</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> Home;
</code></pre>
<p>Let's understand the <code>deleteHandler</code> method first. In this method we use the Supabase client to delete a record from the <strong>todos</strong> table. Once it's successfully deleted, we use the <code>filter</code> method to remove the todo from our local state.</p>
<p>For the useEffect which has the <code>todoListener</code> we add an <code>if</code> condition based on an <code>event</code> type. We don't want to do anything on the <code>DELETE</code> event as we are updating the local state in <code>deleteHandler</code>.</p>
<p>Go to <code>http://localhost:3000</code> and you'll see the following view:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-07-at-1.37.34-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click the <strong>Delete</strong> button and you'll see that the todo is gone from our todos view.</p>
<p>With this we have completed our <strong>TODO CRUD</strong> operation flow.</p>
<h2 id="heading-how-to-update-profile-details-and-avatars">How to Update Profile Details and Avatars</h2>
<p>The <strong>Profile Update Operation</strong> <strong>code</strong> is available under this commit if you need to refer to it in the future for reference.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/Sharvin26/TodoApp-supabase/tree/fb7055b83c847709cb6cc5c6aa26553ecee4026f">https://github.com/Sharvin26/TodoApp-supabase/tree/fb7055b83c847709cb6cc5c6aa26553ecee4026f</a></div>
<p> </p>
<p>Before working on the profile section we have to make our <strong>TodoApp</strong> Heading as a route so we can go back to the home page from the profile page.</p>
<p>In <code>Navbar.js</code> under the components directory replace the existing code with the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Box, Button, ButtonGroup, Flex, Heading } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
<span class="hljs-keyword">import</span> NavLink <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</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> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { supabaseClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/client"</span>;

<span class="hljs-keyword">const</span> Navbar = <span class="hljs-function">(<span class="hljs-params">{ onOpen }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> router = useRouter();
  <span class="hljs-keyword">const</span> [isLogoutLoading, setIsLogoutLoading] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> logoutHandler = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      setIsLogoutLoading(<span class="hljs-literal">true</span>);
      <span class="hljs-keyword">await</span> supabaseClient.auth.signOut();
      router.push(<span class="hljs-string">"/signin"</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      router.push(<span class="hljs-string">"/signin"</span>);
    } <span class="hljs-keyword">finally</span> {
      setIsLogoutLoading(<span class="hljs-literal">false</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">height</span>=<span class="hljs-string">"100%"</span> <span class="hljs-attr">p</span>=<span class="hljs-string">"5"</span> <span class="hljs-attr">bg</span>=<span class="hljs-string">"gray.100"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">maxW</span>=<span class="hljs-string">"6xl"</span> <span class="hljs-attr">mx</span>=<span class="hljs-string">"auto"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Flex</span>
          <span class="hljs-attr">as</span>=<span class="hljs-string">"nav"</span>
          <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Site navigation"</span>
          <span class="hljs-attr">align</span>=<span class="hljs-string">"center"</span>
          <span class="hljs-attr">justify</span>=<span class="hljs-string">"space-between"</span>
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">NavLink</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">mr</span>=<span class="hljs-string">"4"</span> <span class="hljs-attr">as</span>=<span class="hljs-string">"button"</span>&gt;</span>
              TodoApp
            <span class="hljs-tag">&lt;/<span class="hljs-name">Heading</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">NavLink</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">NavLink</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/profile"</span>&gt;</span>Profile<span class="hljs-tag">&lt;/<span class="hljs-name">NavLink</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ButtonGroup</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">"4"</span> <span class="hljs-attr">ml</span>=<span class="hljs-string">"6"</span>&gt;</span>
              {router.pathname === "/" &amp;&amp; (
                <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"blue"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onOpen}</span>&gt;</span>
                  Add Todo
                <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
              )}
              <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
                <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"red"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{logoutHandler}</span>
                <span class="hljs-attr">isLoading</span>=<span class="hljs-string">{isLogoutLoading}</span>
              &gt;</span>
                Logout
              <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ButtonGroup</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">Box</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">default</span> Navbar;
</code></pre>
<p>Let's start working on building the last part of our app which is the profile section. This section will have a form which can update the username, website, bio and an avatar.</p>
<p>To store our pictures we will be using Supabase storage. By default these storage buckets are private and can be accessed using a token. But for the sake of this article we will make the bucket public. But if you are storing any sensitive information make sure to keep that bucket private.</p>
<p>Go to <a target="_blank" href="https://app.supabase.io/">https://app.supabase.io/</a> and go to the storage tab. There you'll see the <code>avatars</code> listed under All Buckets.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-07-at-7.43.07-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click on the three dots and select the <strong>Make public</strong> option.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-07-at-7.43.31-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Back to our code: inside the <strong>pages</strong> directory create a file named <code>profile.js</code> and copy paste the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> {
  Avatar,
  Box,
  Button,
  Flex,
  FormControl,
  FormLabel,
  Input,
  Stack,
  Textarea,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
<span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Navbar"</span>;
<span class="hljs-keyword">import</span> { supabaseClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/client"</span>;

<span class="hljs-keyword">const</span> Profile = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [email, setEmail] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [website, setWebsite] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [bio, setBio] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [avatarurl, setAvatarurl] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [isImageUploadLoading, setIsImageUploadLoading] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> user = supabaseClient.auth.user();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (user) {
      setEmail(user.email);
      supabaseClient
        .from(<span class="hljs-string">"profiles"</span>)
        .select(<span class="hljs-string">"*"</span>)
        .eq(<span class="hljs-string">"id"</span>, user.id)
        .then(<span class="hljs-function">(<span class="hljs-params">{ data, error }</span>) =&gt;</span> {
          <span class="hljs-keyword">if</span> (!error) {
            setUsername(data[<span class="hljs-number">0</span>].username || <span class="hljs-string">""</span>);
            setWebsite(data[<span class="hljs-number">0</span>].website || <span class="hljs-string">""</span>);
            setBio(data[<span class="hljs-number">0</span>].bio || <span class="hljs-string">""</span>);
            setAvatarurl(data[<span class="hljs-number">0</span>].avatarurl || <span class="hljs-string">""</span>);
          }
        });
    }
  }, [user]);

  <span class="hljs-keyword">const</span> updateHandler = <span class="hljs-keyword">async</span> (event) =&gt; {
    event.preventDefault();
    setIsLoading(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">const</span> body = { username, website, bio };
    <span class="hljs-keyword">const</span> userId = user.id;
    <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabaseClient
      .from(<span class="hljs-string">"profiles"</span>)
      .update(body)
      .eq(<span class="hljs-string">"id"</span>, userId);
    <span class="hljs-keyword">if</span> (!error) {
      setUsername(body.username);
      setWebsite(body.website);
      setBio(body.bio);
    }
    setIsLoading(<span class="hljs-literal">false</span>);
  };

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makeid</span>(<span class="hljs-params">length</span>) </span>{
    <span class="hljs-keyword">let</span> result = <span class="hljs-string">""</span>;
    <span class="hljs-keyword">const</span> characters =
      <span class="hljs-string">"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"</span>;
    <span class="hljs-keyword">const</span> charactersLength = characters.length;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; length; i++) {
      result += characters.charAt(<span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random() * charactersLength));
    }
    <span class="hljs-keyword">return</span> result;
  }

  <span class="hljs-keyword">const</span> uploadHandler = <span class="hljs-keyword">async</span> (event) =&gt; {
    setIsImageUploadLoading(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">const</span> avatarFile = event.target.files[<span class="hljs-number">0</span>];
    <span class="hljs-keyword">const</span> fileName = makeid(<span class="hljs-number">10</span>);

    <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabaseClient.storage
      .from(<span class="hljs-string">"avatars"</span>)
      .upload(fileName, avatarFile, {
        <span class="hljs-attr">cacheControl</span>: <span class="hljs-string">"3600"</span>,
        <span class="hljs-attr">upsert</span>: <span class="hljs-literal">false</span>,
      });
    <span class="hljs-keyword">if</span> (error) {
      setIsImageUploadLoading(<span class="hljs-literal">false</span>);
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"error"</span>, error);
      <span class="hljs-keyword">return</span>;
    }
    <span class="hljs-keyword">const</span> { publicURL, <span class="hljs-attr">error</span>: publicURLError } = supabaseClient.storage
      .from(<span class="hljs-string">"avatars"</span>)
      .getPublicUrl(fileName);
    <span class="hljs-keyword">if</span> (publicURLError) {
      setIsImageUploadLoading(<span class="hljs-literal">false</span>);
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"publicURLError"</span>, publicURLError);
      <span class="hljs-keyword">return</span>;
    }
    <span class="hljs-keyword">const</span> userId = user.id;
    <span class="hljs-keyword">await</span> supabaseClient
      .from(<span class="hljs-string">"profiles"</span>)
      .update({
        <span class="hljs-attr">avatarurl</span>: publicURL,
      })
      .eq(<span class="hljs-string">"id"</span>, userId);
    setAvatarurl(publicURL);
    setIsImageUploadLoading(<span class="hljs-literal">false</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">Navbar</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">mt</span>=<span class="hljs-string">"8"</span> <span class="hljs-attr">maxW</span>=<span class="hljs-string">"xl"</span> <span class="hljs-attr">mx</span>=<span class="hljs-string">"auto"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Flex</span> <span class="hljs-attr">align</span>=<span class="hljs-string">"center"</span> <span class="hljs-attr">justify</span>=<span class="hljs-string">"center"</span> <span class="hljs-attr">direction</span>=<span class="hljs-string">"column"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Avatar</span>
            <span class="hljs-attr">size</span>=<span class="hljs-string">"2xl"</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">{avatarurl</span> || ""}
            <span class="hljs-attr">name</span>=<span class="hljs-string">{username</span> || <span class="hljs-attr">user</span>?<span class="hljs-attr">.email</span>}
          /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span>
            <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"file-input"</span>
            <span class="hljs-attr">my</span>=<span class="hljs-string">"5"</span>
            <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"2xl"</span>
            <span class="hljs-attr">borderWidth</span>=<span class="hljs-string">"1px"</span>
            <span class="hljs-attr">textAlign</span>=<span class="hljs-string">"center"</span>
            <span class="hljs-attr">p</span>=<span class="hljs-string">"2"</span>
            <span class="hljs-attr">bg</span>=<span class="hljs-string">"blue.400"</span>
            <span class="hljs-attr">color</span>=<span class="hljs-string">"white"</span>
          &gt;</span>
            {isImageUploadLoading ? "Uploading....." : "Upload Profile Picture"}
          <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">type</span>=<span class="hljs-string">"file"</span>
            <span class="hljs-attr">hidden</span>
            <span class="hljs-attr">id</span>=<span class="hljs-string">"file-input"</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{uploadHandler}</span>
            <span class="hljs-attr">multiple</span>=<span class="hljs-string">{false}</span>
            <span class="hljs-attr">disabled</span>=<span class="hljs-string">{isImageUploadLoading}</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">Stack</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">overflow</span>=<span class="hljs-string">"hidden"</span>
          <span class="hljs-attr">p</span>=<span class="hljs-string">{5}</span>
          <span class="hljs-attr">mt</span>=<span class="hljs-string">"-2"</span>
          <span class="hljs-attr">spacing</span>=<span class="hljs-string">"4"</span>
          <span class="hljs-attr">as</span>=<span class="hljs-string">"form"</span>
          <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{updateHandler}</span>
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">FormControl</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">isRequired</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span>&gt;</span>Email<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">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">isDisabled</span>=<span class="hljs-string">{true}</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{email}</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">FormControl</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">isRequired</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span>&gt;</span>Username<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">placeholder</span>=<span class="hljs-string">"Add your username here"</span>
              <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
              <span class="hljs-attr">value</span>=<span class="hljs-string">{username}</span>
              <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setUsername(event.target.value)}
            /&gt;
          <span class="hljs-tag">&lt;/<span class="hljs-name">FormControl</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">FormControl</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"website"</span> <span class="hljs-attr">isRequired</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span>&gt;</span>Website URL<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">placeholder</span>=<span class="hljs-string">"Add your website here"</span>
              <span class="hljs-attr">type</span>=<span class="hljs-string">"url"</span>
              <span class="hljs-attr">value</span>=<span class="hljs-string">{website}</span>
              <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setWebsite(event.target.value)}
            /&gt;
          <span class="hljs-tag">&lt;/<span class="hljs-name">FormControl</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">FormControl</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"bio"</span> <span class="hljs-attr">isRequired</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">FormLabel</span>&gt;</span>Bio<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">placeholder</span>=<span class="hljs-string">"Add your bio here"</span>
              <span class="hljs-attr">value</span>=<span class="hljs-string">{bio}</span>
              <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setBio(event.target.value)}
            /&gt;
          <span class="hljs-tag">&lt;/<span class="hljs-name">FormControl</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"blue"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">isLoading</span>=<span class="hljs-string">{isLoading}</span>&gt;</span>
            Update
          <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Stack</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>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Profile;
</code></pre>
<p>Here we have 4 <code>FormControl</code> elements, and each is pre-filled if a value exists. This is possible because on render <code>useEffect</code> runs which uses the Supabase client to fetch the user record from the <code>auth</code> and <code>profiles</code> tables.</p>
<p><strong>Note:</strong> the auth table is maintained by Supabase and can be accessed via client using following command:</p>
<pre><code class="lang-js">supabase.auth.user()
</code></pre>
<p>Except images, other records can be updated using the <code>updateHandler</code> function. This function updates the user record using <code>id</code>.</p>
<p>The <code>uploadHandler</code> function is responsible for uploading the image to the storage bucket and setting the <code>avatarurl</code> in the profiles table for a record based on <code>id</code>.</p>
<p>The <code>upload</code> method from Supabase uploads the image while the <code>getPublicUrl</code> method gives us a public URL of the image. We use the <code>from('profiles').update</code> method to update the record.</p>
<p>Visit <code>http://localhost:3000</code> and click on profile link. You'll see the following view:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-07-at-7.55.59-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now you can use the update method to update your username, website URL, and bio.</p>
<p>With this our TodoApp is completed and ready for production.</p>
<h2 id="heading-how-to-deploy-the-app-to-vercel-and-configure-supabase-authentication">How to Deploy the App to Vercel and Configure Supabase Authentication</h2>
<p>Before deploying the application on Vercel we need to run the <code>npm run build</code> command and check the terminal output to see if we have any errors.</p>
<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/11/Screenshot-2021-04-10-at-4.07.03-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Vercel Dashboard</em></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 <strong>Import</strong> button on the GitHub repository created above:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-07-at-8.29.42-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Vercel Import Project from Github</em></p>
<p>Now it will ask if you want to create a team. Team is a feature available under the <strong>Pro Plan</strong>. By default Vercel is under the <strong>hobby plan</strong>. For now I'll skip that.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-07-at-8.33.19-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Vercel Create Team</em></p>
<p>Now you'll need to add environment variables. Add them from <code>.env.local</code>.</p>
<p>Click on the Accordion that's in front of Environment Variables and add the variables over there as follows:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-07-at-8.34.22-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Vercel Configure Env and Build Settings</em></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/11/Screenshot-2021-11-07-at-8.39.20-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Vercel Deployment Success</em></p>
<p>Now click on the gray box where your application is shown. It will redirect you to a page where you can find preconfigured domain for your applications.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-07-at-8.42.16-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Vercel Project Overview</em></p>
<p>Yes vercel provides subdomains for which we can set a custom domain also. For now we will use the Vercel domain. Copy the first domain under the Domains section and go to your Supabase project.</p>
<p>Go to <strong>Authentication &gt; Settings</strong> and update the <strong>Site URL</strong> and <strong>Additional Redirect URLs</strong> to the copied URL (make sure to add <code>https://</code> in front of the copied URL):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/Screenshot-2021-11-07-at-8.47.27-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Supabase Authentication Settings</em></p>
<p>With this, we have created our production-ready todo 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-thank-you-for-reading">Thank you for reading!</h2>
<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 (@sharvinshah26).</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[ The Ultimate Guide to Python: How to Go From Beginner to Pro ]]>
                </title>
                <description>
                    <![CDATA[ If you have an interest in Data Science, Web Development, Robotics, or IoT you must learn Python. Python has become the fastest-growing programming language due to its heavy usage and wide range of applications. For a beginner or a person from a non-... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/the-ultimate-guide-to-python-from-beginner-to-intermediate-to-pro/</link>
                <guid isPermaLink="false">66d460fb8812486a37369d60</guid>
                
                    <category>
                        <![CDATA[ 100Days100Projects ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python 3 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sharvin Shah ]]>
                </dc:creator>
                <pubDate>Fri, 01 May 2020 16:47:40 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/05/The-Ultimate-Guide-To-Python-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you have an interest in Data Science, Web Development, Robotics, or IoT you must learn Python. Python has become the fastest-growing programming language due to its heavy usage and wide range of applications.</p>
<p>For a beginner or a person from a non-tech background, learning Python is a good choice. The syntax is like talking and writing plain English. For example, consider this syntax which shows its resemblance to the English language.</p>
<pre><code class="lang-python">print(<span class="hljs-string">"Hello folks"</span>)
</code></pre>
<p>We will use <code>Python3</code> in this tutorial as it is widely used. Most of Python's frameworks and libraries support this version.</p>
<blockquote>
<p><strong>Note:</strong> Any version above 3.5.2 supports most of the libraries and frameworks.</p>
</blockquote>
<h2 id="heading-index">Index:</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-introduction">Introduction</a></p>
</li>
<li><p><a class="post-section-overview" href="#installation-">Installation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-python-shell">Python shell</a></p>
</li>
<li><p><a class="post-section-overview" href="#comment-">Comment</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-print">Print</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-indentation">Indentation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-variables">Variables</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-operators">Operators</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conditional-statements">Conditional Statements</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-for-loops">For Loops</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-while-loops">While loops</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-user-input">User Input</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-typecasting">Typecasting</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-dictionaries">Dictionaries</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lists">Lists</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tuples">Tuples</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-sets">Sets</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-functions-and-arguments">Functions and Arguments</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-args">Args</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-keyword-arguments">keyword Arguments</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-default-argument">Default Arguments</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-kwargs">kwargs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-scope">Scope</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-return-statement">Return Statement</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lambda-expression">Lambda Expression</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-list-comprehension">List comprehension</a></p>
</li>
<li><p><a class="post-section-overview" href="#oops-concepts-">OOPS concepts</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-classes">Classes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-methods">Methods</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-objects">Objects</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-constructor">Constructor</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-instance-attributes">Instance attribute</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-class-attributes">Class attributes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-self">Self</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-inheritance">Inheritance</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-super">Super</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-multiple-inheritance">Multiple Inheritance</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-polymorphism">Polymorphism</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-encapsulation">Encapsulation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-decorator">Decorators</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-exceptions">Exceptions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-package-import">Package Import</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-json-handling">JSON Handling</a></p>
</li>
</ol>
<p><strong>Note:</strong> The beginning of this guide is geared towards beginners. If you have intermediate experience in Python, feel free to skip ahead using the links above.</p>
<h2 id="heading-introduction"><strong>Introduction</strong>:</h2>
<p>As per Github's <a target="_blank" href="https://octoverse.github.com/#top-languages">octoverse</a>, Python is the second most used language by developers in 2019.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/Screenshot-2020-04-29-at-6.53.10-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Octoverse graph of how languages have evolved</em></p>
<p>Before learning any language, it's helpful to know how that language came into existence. Well, Python was developed by <a target="_blank" href="https://en.wikipedia.org/wiki/Guido_van_Rossum">Guido van Rossum</a>, a Dutch programmer, and was released in 1991.</p>
<p>Python is an Interpreted language. It uses the <a target="_blank" href="https://en.wikipedia.org/wiki/CPython">CPython</a> Interpreter to compile the Python code to byte code. For a beginner, you don't need to know much about CPython, but you must be aware of how Python works internally.</p>
<p>The philosophy behind Python is that code must be readable. It achieves this with the help of indentation. It supports many programming paradigms like Functional and Object Oriented programming. You will understand more about these as you read through the article.</p>
<p>The basic question that most beginners have in mind is what a language can do. Here are some of the use-cases of Python:</p>
<ul>
<li><p>Server-side development ( Django, Flask )</p>
</li>
<li><p>Data Science ( Pytorch, Tensor-flow )</p>
</li>
<li><p>Data analysis / Visualisation ( Matplotlib )</p>
</li>
<li><p>Scripting ( Beautiful Soup )</p>
</li>
<li><p>Embedded development</p>
</li>
</ul>
<blockquote>
<p><strong>Note:</strong> I do not endorse any of the above-mentioned libraries or frameworks in particular. They are popular and broadly used in their respective domains.</p>
</blockquote>
<h2 id="heading-installation">Installation</h2>
<p>The first step of learning any programming language is installing it. Python comes bundled with most operating systems nowadays. Use the following command in your terminal to check if Python is available:</p>
<pre><code class="lang-shell">python3 --version
</code></pre>
<p>You'll see the following output:</p>
<pre><code class="lang-shell">Python 3.7.0
</code></pre>
<p>Note that your version of Python might be different. If you have Python installed and the version is above 3.5.2 then you can skip this section.</p>
<p>For those who don't have Python installed, follow the steps below:</p>
<ul>
<li><p><a class="post-section-overview" href="#heading-windows-user">Windows User</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-mac-user">Mac User</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-linux-user">Linux User</a></p>
</li>
</ul>
<h3 id="heading-windows-user">Windows User:</h3>
<ul>
<li><p>Go to <a target="_blank" href="https://www.python.org/downloads/">Python's official website</a>.</p>
</li>
<li><p>Click on the download button ( Download Python 3.8.2 ) [ <strong>Note:</strong> The version may differ based on when you are reading this article ]</p>
</li>
<li><p>Go to the path where the package is downloaded and double-click the installer.</p>
</li>
<li><p>Check the box indicating to "Add Python 3.x to PATH" and then click on "Install Now".</p>
</li>
<li><p>Once done you'll get a prompt that "Setup was successful". Check again if python is configured properly using the above command.</p>
</li>
<li><p>To confirm if Python is installed and configured properly, use the command <code>python3 --version</code>.</p>
</li>
</ul>
<h3 id="heading-mac-user">Mac User:</h3>
<ul>
<li><p>First install <a target="_blank" href="https://apps.apple.com/in/app/xcode/id497799835?mt=12">xcode</a> from the app store.</p>
</li>
<li><p>If you want to install Xcode using the terminal then use the following command:</p>
</li>
</ul>
<pre><code class="lang-shell">xcode-select --install
</code></pre>
<ul>
<li>After that, we will use the brew package manager to install Python. To install and configure <a target="_blank" href="https://brew.sh/">brew</a>, use the following command:</li>
</ul>
<pre><code class="lang-shell">/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
</code></pre>
<ul>
<li>Once brew setup is done, use the following command to update any outdated packages:</li>
</ul>
<pre><code class="lang-shell">brew update
</code></pre>
<ul>
<li>Use the following command to install Python:</li>
</ul>
<pre><code class="lang-shell">brew install python3
</code></pre>
<ul>
<li>To confirm if Python is installed and configured properly, use the command <code>python3 --version</code>.</li>
</ul>
<h3 id="heading-linux-user">Linux User:</h3>
<ul>
<li>To install Python using <code>apt</code>, use the following command:</li>
</ul>
<pre><code class="lang-shell">sudo apt install python3
</code></pre>
<ul>
<li>To install the Python using <code>yum</code>, use the following command:</li>
</ul>
<pre><code class="lang-shell">sudo yum install python3
</code></pre>
<ul>
<li>To confirm if Python is installed and configured properly, use the command <code>python3 --version</code>.</li>
</ul>
<h2 id="heading-python-shell">Python shell:</h2>
<p>The shell is one of the most useful tools you'll come across. The Python shell gives us the power to quickly test any concept before integrating it into our application.</p>
<p>Go to the terminal or command line prompt. Enter <code>python3</code> command and you'll get the following output:</p>
<pre><code class="lang-shell">➜ python3.7
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 26 2018, 23:26:24)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt;
</code></pre>
<p>In this tutorial, we will learn some concepts with the help of the python3 shell which you can see above. From now on, whenever I mention <strong>go to the Python shell</strong>, it means that you have to use the <code>python3</code> command.</p>
<p>To learn the remaining concepts we will create a file called "testing" with the extension <code>.py</code>. To run this file we will use the following command:</p>
<pre><code class="lang-shell">python3 testing.py
</code></pre>
<p>Let's go to the Python shell. Type <code>10 + 12</code> after the <code>&gt;&gt;&gt;</code> mark. You'll get the output 22:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-number">10</span> + <span class="hljs-number">12</span>
<span class="hljs-number">22</span>
</code></pre>
<h2 id="heading-commenting">Commenting:</h2>
<p>Comments make it easy to write code as they help us (and others) understand why a particular piece of code was written. Another awesome thing about comments is that they help improve the readability of the code.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Stay Safe</span>
</code></pre>
<p>When you add the above syntax, the Python interpreter understands that it is a comment. Everything after <code>#</code> is not executed.</p>
<p>You may be wondering why you should use comments. Imagine you are a developer and you have been assigned to a huge project. The project has more than a thousand lines of code. To understand how everything works you'll need to go line by line and read through all the code.</p>
<p>What's a better solution than that? Ah-ha! Comments. Comments help us understand why a particular piece of code was written and what it returns or does. Consider it as documentation for every piece of code.</p>
<h2 id="heading-print">Print:</h2>
<p>Other than debugging tools from the editor, the thing which helps developers solve problems most often is a print statement. The print statement is one of the most underrated pieces of syntax in all of programming.</p>
<p>So how does it help in debugging an issue? Well, consider that you have a module and you want to check the flow of execution to understand or debug it. There are two options. Either you can use a debugger or add a print statement.</p>
<p>It's not always possible to use a debugger. For example, if you are using the Python shell, then a debugger is not available. In such a scenario, print helps us. Another scenario is when your application is running. You can add a print statement that will display in the logs of your application and monitor them in runtime.</p>
<p>Python provides a inbuilt print method with the following syntax:</p>
<pre><code class="lang-python">print(<span class="hljs-string">"Stay safe..."</span>)
</code></pre>
<h2 id="heading-indentation">Indentation:</h2>
<p>Another interesting part of this language is indentation. Why? Well, the answer is simple: It makes the code readable and well-formatted. It is compulsory in Python to follow the rules of indentation. If proper indentation is not followed you'll get the following error:</p>
<pre><code class="lang-python">IndentationError: unexpected indent
</code></pre>
<p>See, even the errors in Python are so readable and easy to understand. At the start, you may be annoyed by the compulsion of indentation. But with the time you'll understand that indentation is a developer's friend.</p>
<h2 id="heading-variables"><strong>Variables:</strong></h2>
<p>As the name implies, a variable is something that can change. A variable is a way of referring to a memory location used by a computer program.</p>
<p>Well in most programming languages you need to assign the type to a variable. But in Python, you don’t need to. For example, to declare an integer in C, the following syntax is used: <code>int num = 5;</code>. In Python it's <code>num = 5</code> .</p>
<p>Go to the Python shell and perform the operation step by step:</p>
<ul>
<li><code>Integer</code>: Numerical values that can be positive, negative, or zero without a decimal point.</li>
</ul>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>num = <span class="hljs-number">5</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>print(num)
<span class="hljs-number">5</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>type(num)
&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> '<span class="hljs-title">int</span>'&gt;</span>
</code></pre>
<p>As you can see here we have declared a <code>num</code> variable and assigned 5 as a value. Python's inbuilt <code>type</code> method can be used to check the type of variable. When we check the type of <code>num</code> we see the output <code>&lt;class 'int'&gt;</code>. For now, just focus on the <code>int</code> in that output. <code>int</code> represents an integer.</p>
<ul>
<li><code>Float</code>: Similar an integer but with one slight difference – floats are a numerical value with a decimal place.</li>
</ul>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>num = <span class="hljs-number">5.0</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>print(num)
<span class="hljs-number">5.0</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>type(num)
&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> '<span class="hljs-title">float</span>'&gt;</span>
</code></pre>
<p>Here we have assigned a number with a single decimal to the <code>num</code>. When we check the type of <code>num</code> we can see it is <code>float</code>.</p>
<ul>
<li><code>String</code>: A formation of characters or integers. They can be represented using double or single quotes.</li>
</ul>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>greet = <span class="hljs-string">"Hello user"</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>print(greet)
Hello user
<span class="hljs-meta">&gt;&gt;&gt; </span>type(greet)
&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> '<span class="hljs-title">str</span>'&gt;</span>
</code></pre>
<p>Here we have assigned a string to <code>greet</code>. The type of greet is a string as you can see from the output.</p>
<ul>
<li><code>Boolean</code>: A binary operator with a True or False value.</li>
</ul>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>is_available = <span class="hljs-literal">True</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>print(is_available)
<span class="hljs-literal">True</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>type(is_available)
&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> '<span class="hljs-title">bool</span>'&gt;</span>
</code></pre>
<p>Here we have assigned a True value to <code>is_available</code>. The type of this variable is boolean. You can only assign <strong>True</strong> or <strong>False</strong>. Remember <strong>T</strong> and <strong>F</strong> should be capital or it will give an error as follows:</p>
<pre><code class="lang-shell">&gt;&gt;&gt; is_available = true
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
NameError: name 'true' is not defined
</code></pre>
<ul>
<li><code>NoneType</code>: This is used when we don't have the value of the variable.</li>
</ul>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>num = <span class="hljs-literal">None</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>print(num)
<span class="hljs-literal">None</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>type(num)
&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> '<span class="hljs-title">NoneType</span>'&gt;</span>
</code></pre>
<h2 id="heading-operators">Operators:</h2>
<p>Take a look at the image below to see all the arithmetic operators available in Python:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/Screenshot-2020-04-30-at-12.28.55-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Operators table</em></p>
<p>Let's go over the operators one by one.</p>
<h3 id="heading-arithmetic-operators">Arithmetic operators</h3>
<p>These include addition, subtraction, deletion, exponentiation, modulus, and floor division. Also the shorthand syntax for some operators.</p>
<p>First, we will declare two variables, <code>a</code> and <code>b</code>.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>a = <span class="hljs-number">6</span> <span class="hljs-comment"># Assignment</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>b = <span class="hljs-number">2</span>
</code></pre>
<p>Let's try our basic arithmetic operations:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>a + b <span class="hljs-comment"># Addition</span>
<span class="hljs-number">8</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a - b <span class="hljs-comment"># Subtraction</span>
<span class="hljs-number">4</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a * b <span class="hljs-comment"># Multiplication</span>
<span class="hljs-number">12</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a / b <span class="hljs-comment"># Division</span>
<span class="hljs-number">3.0</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a ** b <span class="hljs-comment"># Exponentiation</span>
<span class="hljs-number">36</span>
</code></pre>
<p>To test for other arithmetic operations let's change the value of <code>a</code> and <code>b</code>.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>a = <span class="hljs-number">7</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>b = <span class="hljs-number">3</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a % b <span class="hljs-comment"># Modulus</span>
<span class="hljs-number">1</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a // b <span class="hljs-comment"># Floor division</span>
<span class="hljs-number">2</span>
</code></pre>
<p>Shorthand arithmetic operations are also available in Python. Refer back to the image above to test them out. To print the output of the shorthand operations use the <code>print</code> statement.</p>
<h3 id="heading-comparison-operators">Comparison operators</h3>
<p>These include equal to, greater than, and less than.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>a = <span class="hljs-number">5</span> <span class="hljs-comment"># Assign</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>b = <span class="hljs-number">2</span> <span class="hljs-comment"># Assign</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a &gt; b <span class="hljs-comment"># Greater than</span>
<span class="hljs-literal">True</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a &lt; b <span class="hljs-comment"># less then</span>
<span class="hljs-literal">False</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a == b <span class="hljs-comment"># Equal to</span>
<span class="hljs-literal">False</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a &gt;= <span class="hljs-number">5</span> <span class="hljs-comment"># Greater than or equal to</span>
<span class="hljs-literal">True</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>b &lt;= <span class="hljs-number">1</span> <span class="hljs-comment"># Less than or equal to</span>
<span class="hljs-literal">False</span>
</code></pre>
<h3 id="heading-logical-operators">Logical operators</h3>
<p>These operators include not, and, &amp; or.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>a = <span class="hljs-number">10</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>b = <span class="hljs-number">2</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a == <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> b == <span class="hljs-number">10</span> <span class="hljs-comment"># and</span>
<span class="hljs-literal">False</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a == <span class="hljs-number">10</span> <span class="hljs-keyword">or</span> b == <span class="hljs-number">10</span> <span class="hljs-comment"># or</span>
<span class="hljs-literal">True</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">not</span>(a == <span class="hljs-number">10</span>) <span class="hljs-comment"># not</span>
<span class="hljs-literal">False</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">not</span>(a == <span class="hljs-number">2</span>)
<span class="hljs-literal">True</span>
</code></pre>
<h2 id="heading-conditional-statements">Conditional Statements:</h2>
<p>As the name suggests, conditional statements are used to evaluate if a condition is true or false.</p>
<p>Many times when you are developing an application you need to check a certain condition and do different things depending on the outcome. In such scenarios conditional statements are useful. If, elif and else are the conditional statements used in Python.</p>
<p>We can compare variables, check if the variable has any value or if it's a boolean, then check if it's true or false. Go to the Python shell and perform the operation step by step:</p>
<p><strong>Condition Number 1:</strong> We have an integer and 3 conditions here. The first one is the <code>if</code> condition. It checks if the number is equal to 10.</p>
<p>The second one is the <code>elif</code> condition. Here we are checking if the number is less than 10.</p>
<p>The last condition is <code>else</code>. This condition executes when none of the above conditions match.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>number = <span class="hljs-number">5</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">if</span> number == <span class="hljs-number">10</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Number is 10"</span>)
<span class="hljs-meta">... </span><span class="hljs-keyword">elif</span> number &lt; <span class="hljs-number">10</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Number is less than 10"</span>)
<span class="hljs-meta">... </span><span class="hljs-keyword">else</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Number is more than 10"</span>)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Number is less than 10
</code></pre>
<p><strong>Note:</strong> It is not compulsory to check that two conditions are equal in the <code>if</code> condition. You can do it in the <code>elif</code> also.</p>
<p><strong>Condition Number 2:</strong> We have a boolean and 2 conditions here. Have you noticed how we are checking if the condition is true? If <code>is_available</code>, then print "Yes it is available", else print "Not available".</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>is_available = <span class="hljs-literal">True</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">if</span> is_available:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Yes it is available"</span>)
<span class="hljs-meta">... </span><span class="hljs-keyword">else</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Not available"</span>)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Yes it is available
</code></pre>
<p><strong>Condition Number 3:</strong> Here we have reversed condition number 2 with the help of the not operator.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>is_available = <span class="hljs-literal">True</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> is_available:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Not available"</span>)
<span class="hljs-meta">... </span><span class="hljs-keyword">else</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Yes it is available"</span>)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Yes it is available
</code></pre>
<p><strong>Condition Number 4:</strong> Here we are declaring the data as None and checking if the data is available or not.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data = <span class="hljs-literal">None</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">if</span> data:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"data is not none"</span>)
<span class="hljs-meta">... </span><span class="hljs-keyword">else</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"data is none"</span>)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">data is none
</code></pre>
<p><strong>Condition Number 5:</strong> You can also use an inline if in Python. The syntax to achieve this is the following:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>num_a = <span class="hljs-number">10</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>num_b = <span class="hljs-number">5</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">if</span> num_a &gt; num_b: print(<span class="hljs-string">"num_a is greater than num_b"</span>)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">num_a is greater than num_b
</code></pre>
<p><strong>Condition Number 6:</strong> You can also use an inline if else in Python. The syntax to achieve this is the following:</p>
<pre><code class="lang-python">expression_if_true <span class="hljs-keyword">if</span> condition <span class="hljs-keyword">else</span> expression_if_false
</code></pre>
<p>Example:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>num = <span class="hljs-number">5</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>print(<span class="hljs-string">"Number is five"</span>) <span class="hljs-keyword">if</span> num == <span class="hljs-number">5</span> <span class="hljs-keyword">else</span> print(<span class="hljs-string">"Number is not five"</span>)
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Number is five
</code></pre>
<p><strong>Conditional Number 7:</strong> You can also use nested if-else statements. The syntax to achieve this is the following:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>num = <span class="hljs-number">25</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">if</span> num &gt; <span class="hljs-number">10</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Number is greater than 10"</span>)
<span class="hljs-meta">... </span>    <span class="hljs-keyword">if</span> num &gt; <span class="hljs-number">20</span>:
<span class="hljs-meta">... </span>            print(<span class="hljs-string">"Number is greater than 20"</span>)
<span class="hljs-meta">... </span>    <span class="hljs-keyword">if</span> num &gt; <span class="hljs-number">30</span>:
<span class="hljs-meta">... </span>            print(<span class="hljs-string">"Number is greater than 30"</span>)
<span class="hljs-meta">... </span><span class="hljs-keyword">else</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Number is smaller than 10"</span>)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Number is greater than 10
Number is greater than 20
</code></pre>
<p><strong>Condition Number 8:</strong> You can also use the <code>and</code> operator in a conditional statement. It states if condition1 and condition2 both are true then execute it.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>num = <span class="hljs-number">10</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">if</span> num &gt; <span class="hljs-number">5</span> <span class="hljs-keyword">and</span> num &lt; <span class="hljs-number">15</span>:
<span class="hljs-meta">... </span>    print(num)
<span class="hljs-meta">... </span><span class="hljs-keyword">else</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Number may be small than 5 or larger than 15"</span>)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">10
</code></pre>
<p>As our number is between 5 and 15 we get the output of 10.</p>
<p><strong>Condition Number 9:</strong> You can also use the <code>or</code> operator in a conditional statement. It states that if either condition1 or condition2 is true then execute it.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>num = <span class="hljs-number">10</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">if</span> num &gt; <span class="hljs-number">5</span> <span class="hljs-keyword">or</span> num &lt; <span class="hljs-number">7</span>:
<span class="hljs-meta">... </span>    print(num)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">10
</code></pre>
<p>Are you confused because the value of <code>num</code> is 10 and our second condition states that <code>num</code> is less than 7? So why do we get the output as 10? It's because of the <code>or</code> condition. As one of the conditions matches, it will execute it.</p>
<h2 id="heading-for-loops">For Loops:</h2>
<p>Another useful method in any programming language is an iterator. If you have to implement something multiple times, what will you do?</p>
<pre><code class="lang-python">print(<span class="hljs-string">"Hello"</span>)
print(<span class="hljs-string">"Hello"</span>)
print(<span class="hljs-string">"Hello"</span>)
</code></pre>
<p>Well, that's one way to do it. But imagine you have to do it a hundred or a thousand times. Well, that's a lot of print statements we have to write. There's a better way called iterators or loops. We can either use a <code>for</code> or <code>while</code> loop.</p>
<p>Here we are using the range method. It specifies the range until which the loop should be repeated. By default, the starting point is 0.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">3</span>):
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Hello"</span>)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Hello
Hello
Hello
</code></pre>
<p>You can also specify the range in this way <code>range(1,3)</code>.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">3</span>):
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Hello"</span>)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Hello
Hello
</code></pre>
<p>"Hello" is only printed two times as we have specified the range here. Think of the range as <code>Number on right - Number on left</code>.</p>
<p>Well, you can also add an else statement in the for loop.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">3</span>):
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Hello"</span>)
<span class="hljs-meta">... </span><span class="hljs-keyword">else</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Finished"</span>)
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Hello
Hello
Hello
Finished
</code></pre>
<p>See our loop iterated 3 times ( 3 - 0 ) and once that is done it executed the else statement.</p>
<p>We can also nest a for loop inside another for loop.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">3</span>):
<span class="hljs-meta">... </span>    <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>):
<span class="hljs-meta">... </span>            print(<span class="hljs-string">"Inner loop"</span>)
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Outer loop"</span>)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Inner loop
Inner loop
Outer loop
Inner loop
Inner loop
Outer loop
Inner loop
Inner loop
Outer loop
</code></pre>
<p>As you can see the inner loop print statement executed two times. After that outer loop print statement executed. Again the inner loop executed two times. So what is happening here? If you are confused then consider this to solve it:</p>
<ul>
<li><p>Our Interpreter comes and sees that there is a <code>for</code> loop. It goes down again and checks there is another <code>for</code> loop.</p>
</li>
<li><p>So now it will execute the inner <code>for</code> loop two times and exit. Once it's finished it knows that outer for loop has instructed it to repeat two more times.</p>
</li>
<li><p>It starts again and sees the inner for loop and repeats.</p>
</li>
</ul>
<p>Well, you can also choose to pass a certain <code>for</code> loop condition. What does pass mean here? Well whenever that for loop will occur and the Interpreter sees the <code>pass</code> statement it won't execute it and will move to the next line.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">3</span>):
<span class="hljs-meta">... </span>    <span class="hljs-keyword">pass</span>
...
</code></pre>
<p>You will not get any output on the shell.</p>
<h2 id="heading-while-loops">While loops:</h2>
<p>Another loop or iterator available in Python is the <code>while</code> loop. We can achieve some of the same results with the help of a <code>while</code> loop as we achieved with the <code>for</code> loop.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>i = <span class="hljs-number">0</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">while</span> i &lt; <span class="hljs-number">5</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Number"</span>, i)
<span class="hljs-meta">... </span>    i += <span class="hljs-number">1</span>
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Number 0
Number 1
Number 2
Number 3
Number 4
</code></pre>
<p>Remember whenever you use a while loop it's important that you add an increment statement or a statement that will end the while loop at some point. If not then the while loop will execute forever.</p>
<p>Another option is to add a <code>break</code> statement in a <code>while</code> loop. This will break the loop.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>i = <span class="hljs-number">0</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">while</span> i &lt; <span class="hljs-number">5</span>:
<span class="hljs-meta">... </span>    <span class="hljs-keyword">if</span> i == <span class="hljs-number">4</span>:
<span class="hljs-meta">... </span>            <span class="hljs-keyword">break</span>
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Number"</span>, i)
<span class="hljs-meta">... </span>    i += <span class="hljs-number">1</span>
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Number 0
Number 1
Number 2
Number 3
</code></pre>
<p>Here we are breaking the <code>while</code> loop if we find the value of <code>i</code> to be 4.</p>
<p>Another option is to add an <code>else</code> statement in <code>while</code> loop. The statement will be executed after the while loop is completed.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>i = <span class="hljs-number">0</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">while</span> i &lt; <span class="hljs-number">5</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Number"</span>, i)
<span class="hljs-meta">... </span>    i += <span class="hljs-number">1</span>
<span class="hljs-meta">... </span><span class="hljs-keyword">else</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Number is greater than 4"</span>)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Number 0
Number 1
Number 2
Number 3
Number 4
Number is greater than 4
</code></pre>
<p>The <code>continue</code> statement can be used to skip the current execution and to proceed to the next.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>i = <span class="hljs-number">0</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">while</span> i &lt; <span class="hljs-number">6</span>:
<span class="hljs-meta">... </span>    i += <span class="hljs-number">1</span>
<span class="hljs-meta">... </span>    <span class="hljs-keyword">if</span> i == <span class="hljs-number">2</span>:
<span class="hljs-meta">... </span>            <span class="hljs-keyword">continue</span>
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"number"</span>, i)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">number 1
number 3
number 4
number 5
number 6
</code></pre>
<h2 id="heading-user-input">User Input:</h2>
<p>Imagine you are building a command-line application. Now you have to take the user input and act accordingly. To do that you can use Python's inbuilt <code>input</code> method.</p>
<p>The syntax to achieve this is as follows:</p>
<pre><code class="lang-python">variable = input(<span class="hljs-string">"....."</span>)
</code></pre>
<p>Example:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>name = input(<span class="hljs-string">"Enter your name: "</span>)
Enter your name: Sharvin
</code></pre>
<p>When you use the <code>input</code> method and press enter, you'll be prompted with the text that you enter in the <code>input</code> method. Let's check if our assignment is working or not:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>print(name)
Sharvin
</code></pre>
<p>There it is! It is working perfectly. Here <code>Sharvin</code> is of the type string.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>type(name)
&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> '<span class="hljs-title">str</span>'&gt;</span>
</code></pre>
<p>Let's try one more example where we will assign an integer rather than a string and check the type.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>date = input(<span class="hljs-string">"Today's date: "</span>)
Today<span class="hljs-string">'s date: 12
&gt;&gt;&gt; type(date)
&lt;class '</span>st<span class="hljs-string">r'&gt;</span>
</code></pre>
<p>Are you confused? We entered an integer 12 and it's still giving us its type as a string. It's not a bug. It's how input is intended to work. To convert the string to integer we will use typecasting.</p>
<h2 id="heading-typecasting">Typecasting:</h2>
<p>We saw that the <code>input</code> method returns a string for the integer also. Now if we want to compare this output with another integer then we need a way to convert it back to an integer.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>date_to_int = int(date)
<span class="hljs-meta">&gt;&gt;&gt; </span>type(date_to_int)
&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> '<span class="hljs-title">int</span>'&gt;</span>
</code></pre>
<p>Here we took the date that we have declared above in the User input section and converted it into the integer using the Python's inbuilt <code>int</code> method. This is called typecasting.</p>
<p>Basically you can do the following conversion with the help of typecasting:</p>
<ul>
<li><p>integer to string: <code>str()</code></p>
</li>
<li><p>string to integer: <code>int()</code></p>
</li>
<li><p>integer to float: <code>float()</code></p>
</li>
</ul>
<blockquote>
<p>Note: Conversion from float to integer is also possible.</p>
</blockquote>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>type(date)
&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> '<span class="hljs-title">str</span>'&gt;

# <span class="hljs-title">Converting</span> <span class="hljs-title">from</span> <span class="hljs-title">string</span> <span class="hljs-title">to</span> <span class="hljs-title">float</span>
&gt;&gt;&gt; <span class="hljs-title">date_to_float</span> = <span class="hljs-title">float</span>(<span class="hljs-params">date</span>)
&gt;&gt;&gt; <span class="hljs-title">type</span>(<span class="hljs-params">date_to_float</span>)
&lt;<span class="hljs-title">class</span> '<span class="hljs-title">float</span>'&gt;

# <span class="hljs-title">Converting</span> <span class="hljs-title">from</span> <span class="hljs-title">float</span> <span class="hljs-title">to</span> <span class="hljs-title">string</span>
&gt;&gt;&gt; <span class="hljs-title">date_to_string</span> = <span class="hljs-title">str</span>(<span class="hljs-params">date_to_float</span>)
&gt;&gt;&gt; <span class="hljs-title">type</span>(<span class="hljs-params">date_to_string</span>)
&lt;<span class="hljs-title">class</span> '<span class="hljs-title">str</span>'&gt;

# <span class="hljs-title">Converting</span> <span class="hljs-title">from</span> <span class="hljs-title">float</span> <span class="hljs-title">to</span> <span class="hljs-title">integer</span>
&gt;&gt;&gt; <span class="hljs-title">date_to_int</span> = <span class="hljs-title">int</span>(<span class="hljs-params">date_to_float</span>)
&gt;&gt;&gt; <span class="hljs-title">type</span>(<span class="hljs-params">date_to_int</span>)
&lt;<span class="hljs-title">class</span> '<span class="hljs-title">int</span>'&gt;</span>
</code></pre>
<h2 id="heading-dictionaries">Dictionaries:</h2>
<p>Imagine you want to store some user details. So how can you store these details? Yes, we can use variable to store them as follows:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>fname = <span class="hljs-string">"Sharvin"</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>lname = <span class="hljs-string">"Shah"</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>profession = <span class="hljs-string">"Developer"</span>
</code></pre>
<p>To access this value we can do the following:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>print(fname)
Sharvin
</code></pre>
<p>But is this an elegant and optimized way to access it? The answer is no. To make it more friendly, let's store the data in a key-value dictionary.</p>
<p>What is a dictionary? A dictionary is a collection that is unordered and mutable ( i.e. it can be updated ).</p>
<p>Following is the format of the dictionary:</p>
<pre><code class="lang-json">data = {
    <span class="hljs-attr">"key"</span> : <span class="hljs-string">"value"</span>
}
</code></pre>
<p>Let's understand the dictionary further by an example:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details = {
<span class="hljs-meta">... </span>    <span class="hljs-string">"fname"</span>: <span class="hljs-string">"Sharvin"</span>,
<span class="hljs-meta">... </span>    <span class="hljs-string">"lname"</span>: <span class="hljs-string">"Shah"</span>,
<span class="hljs-meta">... </span>    <span class="hljs-string">"profession"</span>: <span class="hljs-string">"Developer"</span>
<span class="hljs-meta">... </span>}
</code></pre>
<h3 id="heading-how-to-access-a-value-in-a-dictionary">How to access a value in a dictionary</h3>
<p>We can access the value inside a dictionary in two ways. We will take a look at both and then debug them to find out which is better.</p>
<p>Method 1: To access the value of <code>fname</code> key from <code>user_details</code> dictionary we can use the following syntax:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details[<span class="hljs-string">"fname"</span>]
<span class="hljs-string">'Sharvin'</span>
</code></pre>
<p>Method 2: We can also access the value of <code>fname</code> key from <code>user_details</code> dictionary using <code>get</code>.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details.get(<span class="hljs-string">"fname"</span>)
<span class="hljs-string">'Sharvin'</span>
</code></pre>
<p>I know method 1 looks easier to understand. The problem with it occurs when we try to access the data that is not available in our dictionary.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details[<span class="hljs-string">"age"</span>]
Traceback (most recent call last):
  File <span class="hljs-string">"&lt;stdin&gt;"</span>, line <span class="hljs-number">1</span>, <span class="hljs-keyword">in</span> &lt;module&gt;
KeyError: <span class="hljs-string">'age'</span>
</code></pre>
<p>We get a KeyError which indicates that the key is not available. Let's try the same scenario with method 2.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details.get(<span class="hljs-string">"age"</span>)
</code></pre>
<p>We do not get anything printed in our console. Let's debug it further to know why this happened. Assign a variable age to our <code>get</code> operation and we will print it in our console.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>age = user_details.get(<span class="hljs-string">"age"</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>print(age)
<span class="hljs-literal">None</span>
</code></pre>
<p>So when <code>get</code> doesn't find the key it sets the value to None. Because of this, we do not get any error. Now you may be wondering which one is right. Most of the time using method 2 makes more sense, but for some strict checking conditions, we need to use method 1.</p>
<h3 id="heading-how-to-check-if-a-key-exists">How to check if a key exists</h3>
<p>You may be wondering how to check if the dictionary has a particular key or not in it. Python provides the built-in method <code>keys()</code> to solve this issue.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">if</span> <span class="hljs-string">"age"</span> <span class="hljs-keyword">in</span> user_details.keys():
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Yes it is present"</span>)
<span class="hljs-meta">... </span><span class="hljs-keyword">else</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Not present"</span>)
...
</code></pre>
<p>We will get the following output:</p>
<pre><code class="lang-shell">Not present
</code></pre>
<p>What if we want to check if the dictionary is empty or not? To understand this let's declare an empty dictionary as follows:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details = {}
</code></pre>
<p>When we use if-else on a dictionary directly it either returns true if data is present or false if empty.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">if</span> user_details:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Not empty"</span>)
<span class="hljs-meta">... </span><span class="hljs-keyword">else</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Empty"</span>)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Empty
</code></pre>
<p>We can also use Python's inbuilt method <code>bool</code> to check if the dictionary is empty or not. Remember bool returns False if the dictionary is empty and True if it is filled.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>bool(user_details)
<span class="hljs-literal">False</span>

<span class="hljs-meta">&gt;&gt;&gt; </span>user_details = {
<span class="hljs-meta">... </span>    <span class="hljs-string">"fname"</span> : <span class="hljs-string">"Sharvin"</span>
<span class="hljs-meta">... </span>}
<span class="hljs-meta">&gt;&gt;&gt; </span>bool(user_details)
<span class="hljs-literal">True</span>
</code></pre>
<h3 id="heading-how-to-update-the-value-of-an-existing-key">How to update the value of an existing key</h3>
<p>So now we know how to get a particular key and find if it exists – but how do you update it in the dictionary?</p>
<p>Declare a dictionary as follows:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details = {
<span class="hljs-meta">... </span>    <span class="hljs-string">"fname"</span>:<span class="hljs-string">"Sharvin"</span>,
<span class="hljs-meta">... </span>    <span class="hljs-string">"lname"</span>: <span class="hljs-string">"Shah"</span>,
<span class="hljs-meta">... </span>    <span class="hljs-string">"profession"</span>: <span class="hljs-string">"Developer"</span>
<span class="hljs-meta">... </span>}
</code></pre>
<p>To update the value use the following syntax:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details[<span class="hljs-string">"profession"</span>] = <span class="hljs-string">"Software Developer"</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>print(user_details)
{<span class="hljs-string">'fname'</span>: <span class="hljs-string">'Sharvin'</span>, <span class="hljs-string">'lname'</span>: <span class="hljs-string">'Shah'</span>, <span class="hljs-string">'profession'</span>: <span class="hljs-string">'Software Developer'</span>}
</code></pre>
<p>Updating a value of key in dictionary is same as assigning a value to the variable.</p>
<h3 id="heading-how-to-add-a-key-value-pair">How to add a key-value pair</h3>
<p>The next question is how to add a new value to the dictionary? Let's add an <code>age</code> key with a value of 100.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details[<span class="hljs-string">"age"</span>] = <span class="hljs-string">"100"</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>print(user_details)
{<span class="hljs-string">'fname'</span>: <span class="hljs-string">'Sharvin'</span>, <span class="hljs-string">'lname'</span>: <span class="hljs-string">'Shah'</span>, <span class="hljs-string">'profession'</span>: <span class="hljs-string">'Software Developer'</span>, <span class="hljs-string">'age'</span>: <span class="hljs-string">'100'</span>}
</code></pre>
<p>As you can see a new key-value is added in our dictionary.</p>
<h3 id="heading-how-to-remove-a-key-value-pair">How to remove a key-value pair</h3>
<p>To remove a key-value from the dictionary, Python provides an inbuilt method called <code>pop</code>.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details.pop(<span class="hljs-string">"age"</span>)
<span class="hljs-string">'100'</span>

<span class="hljs-meta">&gt;&gt;&gt; </span>print(user_details)
{<span class="hljs-string">'fname'</span>: <span class="hljs-string">'Sharvin'</span>, <span class="hljs-string">'lname'</span>: <span class="hljs-string">'Shah'</span>, <span class="hljs-string">'profession'</span>: <span class="hljs-string">'Software Developer'</span>}
</code></pre>
<p>This removes the <code>age</code> key-value pair from the <code>user_details</code> dictionary. We can also use a <code>del</code> operator to delete the value.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">del</span> user_details[<span class="hljs-string">"age"</span>]

<span class="hljs-meta">&gt;&gt;&gt; </span>print(user_details)
{<span class="hljs-string">'fname'</span>: <span class="hljs-string">'Sharvin'</span>, <span class="hljs-string">'lname'</span>: <span class="hljs-string">'Shah'</span>, <span class="hljs-string">'profession'</span>: <span class="hljs-string">'Software Developer'</span>}
</code></pre>
<p>The <code>del</code> method can also be used to <strong>delete complete dictionary</strong>. Use the following syntax to delete complete dictionary <code>del user_details</code>.</p>
<h3 id="heading-how-to-copy-a-dictionary">How to copy a dictionary</h3>
<p>A dictionary cannot be copied in a traditional way. For example, you cannot copy value of <code>dictA</code> to <code>dictB</code> as follows:</p>
<pre><code class="lang-python">dictA = dictB
</code></pre>
<p>To copy the values you need to use the <code>copy</code> method.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>dictB = user_details.copy()

<span class="hljs-meta">&gt;&gt;&gt; </span>print(dictB)
{<span class="hljs-string">'fname'</span>: <span class="hljs-string">'Sharvin'</span>, <span class="hljs-string">'lname'</span>: <span class="hljs-string">'Shah'</span>, <span class="hljs-string">'profession'</span>: <span class="hljs-string">'Software Developer'</span>}
</code></pre>
<h2 id="heading-lists">Lists:</h2>
<p>Imagine you have a bunch of data that is not labeled. In other words, each piece of data doesn't have a key that defines it. So how will you store it? Lists to the rescue. They are defined as follows:</p>
<pre><code class="lang-python">data = [ <span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-string">"xyz"</span>, <span class="hljs-literal">True</span> ]
</code></pre>
<p>A list is a collection of random, ordered, and mutable data (i.e., it can be updated).</p>
<h3 id="heading-how-to-access-list-elements">How to access list elements</h3>
<p>Let's try to access the first element:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data[<span class="hljs-number">1</span>]
<span class="hljs-number">5</span>
</code></pre>
<p>Wait what happened here? We are trying to access the first element but we are getting the second element. Why?</p>
<p>Indexing of the list begins from zero. So what do I mean by this? The indexing of the position of the elements begins from zero. The syntax to access an element is as follows:</p>
<pre><code class="lang-python">list[position_in_list]
</code></pre>
<p>To access the first element we need to access it as follows:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data[<span class="hljs-number">0</span>]
<span class="hljs-number">1</span>
</code></pre>
<p>You can also specify a range to access the element between those positions.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data[<span class="hljs-number">2</span>:<span class="hljs-number">4</span>]
[<span class="hljs-string">'xyz'</span>, <span class="hljs-literal">True</span>]
</code></pre>
<p>Here, the first value represents the start while the last value represents the position until which we want the value.</p>
<h3 id="heading-how-to-add-an-item-to-a-list">How to add an item to a list</h3>
<p>To add an item in the list we need to use the append method provided by python.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data.append(<span class="hljs-string">"Hello"</span>)

<span class="hljs-meta">&gt;&gt;&gt; </span>data
[<span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-string">'abc'</span>, <span class="hljs-literal">True</span>, <span class="hljs-string">'Hello'</span>]
</code></pre>
<h3 id="heading-how-to-change-the-value-of-an-item">How to change the value of an item</h3>
<p>To change the value of an item, use the following syntax:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data[<span class="hljs-number">2</span>] = <span class="hljs-string">"abc"</span>

<span class="hljs-meta">&gt;&gt;&gt; </span>data
[<span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-string">'abc'</span>, <span class="hljs-literal">True</span>]
</code></pre>
<h3 id="heading-how-to-remove-an-item-from-a-list">How to remove an item from a list</h3>
<p>To remove an item from a list we can use the Python's inbuilt <code>remove</code> method.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data.remove(<span class="hljs-string">"Hello"</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>data
[<span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-string">'abc'</span>, <span class="hljs-literal">True</span>]
</code></pre>
<h3 id="heading-how-to-loop-through-a-list">How to loop through a list</h3>
<p>We can also loop through the list to find a certain element and operate on it.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> data:
<span class="hljs-meta">... </span>    print(i)
...
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">1
5
abc
True
</code></pre>
<h3 id="heading-how-to-check-if-an-item-exists-or-not">How to check if an item exists or not</h3>
<p>To check if a particular item exists or not in list we can use if loop as follows:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">if</span> <span class="hljs-string">'abc'</span> <span class="hljs-keyword">in</span> data:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"yess.."</span>)
...
yess..
</code></pre>
<h3 id="heading-how-to-copy-list-data">How to copy list data</h3>
<p>To copy list data from one list to another we need to use <code>copy</code> method.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>List2 = data.copy()
<span class="hljs-meta">&gt;&gt;&gt; </span>List2
[<span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-string">'abc'</span>, <span class="hljs-literal">True</span>]
</code></pre>
<h3 id="heading-how-to-check-the-length-of-a-list">How to check the length of a list</h3>
<p>We can also check the length of list using Python's inbuilt <code>len</code> method.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>len(data)
<span class="hljs-number">4</span>
</code></pre>
<h3 id="heading-how-to-join-two-lists">How to join two lists</h3>
<p>To join two list we can use the <code>+</code> operator.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>list1 = [<span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">6</span>, <span class="hljs-string">"hello"</span>]
<span class="hljs-meta">&gt;&gt;&gt; </span>list2 = [<span class="hljs-number">2</span>, <span class="hljs-number">8</span>, <span class="hljs-string">"bye"</span>]
<span class="hljs-meta">&gt;&gt;&gt; </span>list1 + list2
[<span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">6</span>, <span class="hljs-string">'hello'</span>, <span class="hljs-number">2</span>, <span class="hljs-number">8</span>, <span class="hljs-string">'bye'</span>]
</code></pre>
<p>What happens if we try to access a element position which is not available in the list? We get a <code>list index out of range error</code> in such a condition.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>list1[<span class="hljs-number">6</span>]
Traceback (most recent call last):
  File <span class="hljs-string">"&lt;stdin&gt;"</span>, line <span class="hljs-number">1</span>, <span class="hljs-keyword">in</span> &lt;module&gt;
IndexError: list index out of range
</code></pre>
<h2 id="heading-tuples">Tuples:</h2>
<p>The tuple is a data type which is ordered and immutable (i.e. data cannot be changed).</p>
<p>Let's create a tuple:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data = ( <span class="hljs-number">1</span>, <span class="hljs-number">3</span> , <span class="hljs-number">5</span>, <span class="hljs-string">"bye"</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>data
(<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>, <span class="hljs-string">'bye'</span>)
</code></pre>
<h3 id="heading-how-to-access-a-tuple-element">How to access a tuple element</h3>
<p>We can access elements in the tuple the same way as we access them in a list:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data[<span class="hljs-number">3</span>]
<span class="hljs-string">'bye'</span>
</code></pre>
<p>We can access the index range as follows:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data[<span class="hljs-number">2</span>:<span class="hljs-number">4</span>]
(<span class="hljs-number">5</span>, <span class="hljs-string">'bye'</span>)
</code></pre>
<h3 id="heading-how-to-change-a-tuples-value">How to change a tuple's value</h3>
<p>If you are thinking wait – how can we change the value of tuple, then you are right my friend. We cannot change the value of tuple as it is immutable. We get the following error if we try to change the value of a tuple:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data[<span class="hljs-number">1</span>] = <span class="hljs-number">8</span>
Traceback (most recent call last):
  File <span class="hljs-string">"&lt;stdin&gt;"</span>, line <span class="hljs-number">1</span>, <span class="hljs-keyword">in</span> &lt;module&gt;
TypeError: <span class="hljs-string">'tuple'</span> object does <span class="hljs-keyword">not</span> support item assignment
</code></pre>
<p>There's a workaround available to change the value of a tuple:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data = ( <span class="hljs-number">1</span>, <span class="hljs-number">3</span> , <span class="hljs-number">5</span>, <span class="hljs-string">"bye"</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>data_two = list(data) <span class="hljs-comment"># Convert data to list</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>data_two[<span class="hljs-number">1</span>] = <span class="hljs-number">8</span> <span class="hljs-comment"># Update value as list is mutable</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>data = tuple(data_two) <span class="hljs-comment"># Convert again to tuple</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>data
(<span class="hljs-number">1</span>, <span class="hljs-number">8</span>, <span class="hljs-number">5</span>, <span class="hljs-string">'bye'</span>)
</code></pre>
<p>All other methods that we have seen in the list are applicable for the tuple also.</p>
<p><strong>[ Note: Once a tuple is created a new value cannot be added in it. ]</strong>.</p>
<h2 id="heading-sets">Sets:</h2>
<p>Sets are another data type in Python which are unordered and unindexed. Sets are declared as follows:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data = { <span class="hljs-string">"hello"</span>, <span class="hljs-string">"bye"</span>, <span class="hljs-number">10</span>, <span class="hljs-number">15</span> }
<span class="hljs-meta">&gt;&gt;&gt; </span>data
{<span class="hljs-number">10</span>, <span class="hljs-number">15</span>, <span class="hljs-string">'hello'</span>, <span class="hljs-string">'bye'</span>}
</code></pre>
<h3 id="heading-how-to-access-a-value">How to access a value</h3>
<p>As sets are unindexed we cannot directly access the value in a set. Thus to access the value in the set you need to use a for loop.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> data:
<span class="hljs-meta">... </span>    print(i)
...

<span class="hljs-number">10</span>
<span class="hljs-number">15</span>
hello
bye
</code></pre>
<h3 id="heading-how-to-change-a-value">How to change a value</h3>
<p>Once the set is created, values cannot be changed.</p>
<h3 id="heading-how-to-add-an-item">How to add an item</h3>
<p>To add an item to the set python provides an inbuilt method called <code>add</code>.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data.add(<span class="hljs-string">"test"</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>data
{<span class="hljs-number">10</span>, <span class="hljs-string">'bye'</span>, <span class="hljs-string">'hello'</span>, <span class="hljs-number">15</span>, <span class="hljs-string">'test'</span>}
</code></pre>
<h3 id="heading-how-to-check-length">How to check length</h3>
<p>To check the length of the set we use the <code>len</code> method.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>len(data)
<span class="hljs-number">5</span>
</code></pre>
<h3 id="heading-how-to-remove-an-item">How to remove an item</h3>
<p>To remove an item use the <code>remove</code> method:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>data.remove(<span class="hljs-string">"test"</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>data
{<span class="hljs-number">10</span>, <span class="hljs-string">'bye'</span>, <span class="hljs-string">'hello'</span>, <span class="hljs-number">15</span>}
</code></pre>
<h2 id="heading-functions-and-arguments">Functions and Arguments:</h2>
<p>Functions are a handy way to declare an operation that we want to perform. With the help of functions, you can separate logic according to the operation.</p>
<p>Functions are a block of code that helps us in the reusability of the repetitive logic. Functions can be both inbuilt and user-defined.</p>
<p>To declare a function we use the <code>def</code> keyword. Following is the syntax of the functions:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">hello_world</span>():</span>
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Hello world"</span>)
...
</code></pre>
<p>Here we are declaring a function which, when called, prints a "Hello world" statement. To call a function we use the following syntax:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>hello_world()
</code></pre>
<p>We will get the following output:</p>
<pre><code class="lang-shell">Hello world
</code></pre>
<p>Remember that the <code>()</code> brackets in a function call means to execute it. Remove those round brackets and try the call again.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>hello_world
</code></pre>
<p>You'll get the following output:</p>
<pre><code class="lang-shell">&lt;function hello_world at 0x1083eb510&gt;
</code></pre>
<p>When we remove the round brackets from the function call then it gives us a function reference. Here above as you can see the reference of <code>function hello_world</code> points to this memory address <code>0x1083eb510</code>.</p>
<p>Consider you have to perform an addition operation. You can do it by declaring <code>a</code> and <code>b</code> and then performing the addition.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>a = <span class="hljs-number">5</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>b = <span class="hljs-number">10</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a + b
<span class="hljs-number">15</span>
</code></pre>
<p>This is one way to go. But now consider that the value of <code>a</code> and <code>b</code> have changed and you need to do it again.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>a = <span class="hljs-number">5</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>b = <span class="hljs-number">10</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a + b
<span class="hljs-number">15</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a = <span class="hljs-number">2</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>b = <span class="hljs-number">11</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>a + b
<span class="hljs-number">13</span>
</code></pre>
<p>This still looks doable. Now imagine we need to add a set of two numbers a hundred times. The numbers within the set are different for every calculation. That's a lot to do. Don't worry – we have a function at our disposal to solve this issue.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add</span>(<span class="hljs-params">a,b</span>):</span>
<span class="hljs-meta">... </span>    print(a+b)
...
</code></pre>
<p>Here we are adding <code>a</code> and <code>b</code> as a compulsory argument to the <code>add</code> function. To call this function we will use the following syntax:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>add(<span class="hljs-number">10</span>,<span class="hljs-number">5</span>)
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">15
</code></pre>
<p>See how easy it is to define a function and use it? So what happens if we don't pass an argument?</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>add()
Traceback (most recent call last):
  File <span class="hljs-string">"&lt;stdin&gt;"</span>, line <span class="hljs-number">1</span>, <span class="hljs-keyword">in</span> &lt;module&gt;
TypeError: add() missing <span class="hljs-number">2</span> required positional arguments: <span class="hljs-string">'a'</span> <span class="hljs-keyword">and</span> <span class="hljs-string">'b'</span>
</code></pre>
<p>Python throws a TypeError and informs us that the function requires two arguments.</p>
<p>Can you guess what will happen if we pass a third argument?</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>add(<span class="hljs-number">10</span>,<span class="hljs-number">5</span>,<span class="hljs-number">1</span>)
Traceback (most recent call last):
  File <span class="hljs-string">"&lt;stdin&gt;"</span>, line <span class="hljs-number">1</span>, <span class="hljs-keyword">in</span> &lt;module&gt;
TypeError: add() takes <span class="hljs-number">2</span> positional arguments but <span class="hljs-number">3</span> were given
</code></pre>
<p>Well, Python will inform us that we have passed 3 arguments but there are only 2 positional arguments.</p>
<p>So what can we do when we don't know how many arguments a function can take? To solve this issue we use args and kwargs.</p>
<h2 id="heading-args">Args:</h2>
<p>When you don't know how many arguments will be passed to the function, use args and kwargs (kwargs are discussed below).</p>
<p>To pass n number of arguments to a function we use args. We add a <code>*</code> in front of the argument.</p>
<blockquote>
<p>Remember when you attach a <code>*</code> in front, you will be receiving a tuple of arguments.</p>
</blockquote>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add</span>(<span class="hljs-params">*num</span>):</span>
<span class="hljs-meta">... </span>    print(num)
...
</code></pre>
<p>Here <code>*num</code> is an instance of args. Now when we call the function <code>add</code> we can pass in n number of arguments and it won't throw a <code>TypeError</code>.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>add(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>)
(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>)

<span class="hljs-meta">&gt;&gt;&gt; </span>add(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>)
(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>)
</code></pre>
<p>Now to perform the addition operation we will use the Python's builtin function <code>sum</code></p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add</span>(<span class="hljs-params">*num</span>):</span>
<span class="hljs-meta">... </span>    print(sum(num))
...
</code></pre>
<p>Now when we call the add function we will get the following output:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>add(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>) <span class="hljs-comment"># Function call</span>
<span class="hljs-number">6</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>add(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>) <span class="hljs-comment"># Function call</span>
<span class="hljs-number">10</span>
</code></pre>
<h2 id="heading-keyword-arguments">Keyword Arguments:</h2>
<p>There are times when we don't know the order of the arguments that will be passed to our function when it's called. In such a scenario we use keyword arguments because you can pass them in any order in your call and our function will know the value. Take a look at this example:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user_details</span>(<span class="hljs-params">username, age</span>):</span>
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Username is"</span>, username)
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Age is"</span>, age)
...
</code></pre>
<p>Let's call this function as follows:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details(<span class="hljs-string">"Sharvin"</span>, <span class="hljs-number">100</span>)
</code></pre>
<p>We will get the following output:</p>
<pre><code class="lang-shell">Username is Sharvin
Age is 100
</code></pre>
<p>Well this looks correct, but imagine if we called our function in this way:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details(<span class="hljs-number">100</span>, <span class="hljs-string">"Sharvin"</span>)
</code></pre>
<p>We will get the following output:</p>
<pre><code class="lang-shell">Username is 100
Age is Sharvin
</code></pre>
<p>This does not look right. What happened is <code>username</code> took the value of 100 while <code>age</code> took the value of "Sharvin". In scenarios like this where we don't know the order of arguments we can use keyword arguments when calling the function:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details(age=<span class="hljs-number">100</span>, username=<span class="hljs-string">"Sharvin"</span>)
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Username is Sharvin
Age is 100
</code></pre>
<h2 id="heading-default-argument">Default Argument:</h2>
<p>Suppose there is a condition where we are not sure if a particular argument will get a value or not when the function is called. In such a scenario we can use Default arguments as follows:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user_details</span>(<span class="hljs-params">username, age = None</span>):</span>
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Username is"</span>, username)
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Age is"</span>, age)
...
</code></pre>
<p>Here we are assigning a <code>None</code> to our age argument. If we don't pass a second argument while calling the function it will take None as a default value.</p>
<p>Let's call the function:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details(<span class="hljs-string">"Sharvin"</span>)
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Username is Sharvin
Age is None
</code></pre>
<p>If we pass in the second argument it will override None and use it as the value.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user_details(<span class="hljs-string">"Sharvin"</span>, <span class="hljs-number">200</span>)
Username <span class="hljs-keyword">is</span> Sharvin
Age <span class="hljs-keyword">is</span> <span class="hljs-number">200</span>
</code></pre>
<p>But what will happen if we assign the first argument in our function as default and the second as a compulsory argument? Go to the Python shell and try this out:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user_details</span>(<span class="hljs-params">username=None, age</span>):</span>
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Username is"</span>, username)
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Age is"</span>, age)
...
</code></pre>
<p>You'll get the following error:</p>
<pre><code class="lang-shell">  File "&lt;stdin&gt;", line 1
SyntaxError: non-default argument follows default argument
</code></pre>
<blockquote>
<p><strong>Remember:</strong> All compulsory arguments must be declared first and then the default argument must be declared.</p>
</blockquote>
<h2 id="heading-kwargs">kwargs:</h2>
<p>There can be a situation where you don't know how many keyword arguments will be passed into the function. In such a scenario we can use Kwargs.</p>
<p>To use kwargs we put <code>**</code> in front of the argument.</p>
<blockquote>
<p><strong>Remember:</strong> When you attach a <code>**</code> in front, you will be receiving a dictionary of arguments.</p>
</blockquote>
<p>Let's understand this by example. We will declare a function which accepts username as it's argument with <code>**</code> in front of it.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user</span>(<span class="hljs-params">**username</span>):</span>
<span class="hljs-meta">... </span>    print(username)
...
</code></pre>
<p>When we call the <code>user</code> function as follows we will receive a dictionary.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user(username1=<span class="hljs-string">"xyz"</span>,username2=<span class="hljs-string">"abc"</span>)
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">{'username1': 'xyz', 'username2': 'abc'}
</code></pre>
<p>So what's happening here? It looks the same as args, right?</p>
<p>No, it's not. In args, you cannot access a particular value by its name as it is in the form of a tuple. Here we get the data in the form of a dictionary so we can easily access the value.</p>
<p>Consider this example:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user</span>(<span class="hljs-params">**user_details</span>):</span>
<span class="hljs-meta">... </span>    print(user_details[<span class="hljs-string">'username'</span>])
...
</code></pre>
<p>Let's call our function:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>user(username=<span class="hljs-string">"Sharvin"</span>,age=<span class="hljs-string">"1000"</span>)
</code></pre>
<p>And you'll get the following output:</p>
<pre><code class="lang-shell">Sharvin
</code></pre>
<h2 id="heading-scope">Scope:</h2>
<p>A scope defines where a variable or function is available. There are two types of scope in Python: Global and Local.</p>
<h3 id="heading-global-scope">Global Scope</h3>
<p>A variable or function created in the main body of Python code is called a global variable or function and is part of the global scope. For example:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>greet = <span class="hljs-string">"Hello world"</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">testing</span>():</span>
<span class="hljs-meta">... </span>    print(greet)
...
<span class="hljs-meta">&gt;&gt;&gt; </span>testing()
Hello world
</code></pre>
<p>Here the variable <code>greet</code> is available globally because it is declared in the body of the program.</p>
<h3 id="heading-local-scope">Local Scope</h3>
<p>A variable or function created inside a function is called a local variable or function and is part of the local scope:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">testing</span>():</span>
<span class="hljs-meta">... </span>    greet = <span class="hljs-string">"Hello world"</span>
<span class="hljs-meta">... </span>    print(greet)
...
<span class="hljs-meta">&gt;&gt;&gt; </span>testing()
Hello world
</code></pre>
<p>Here <code>greet</code> is created inside the testing function and is only available there. Let's try to access it in our main body and see what happens:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>print(greet)
Traceback (most recent call last):
  File <span class="hljs-string">"&lt;stdin&gt;"</span>, line <span class="hljs-number">1</span>, <span class="hljs-keyword">in</span> &lt;module&gt;
NameError: name <span class="hljs-string">'greet'</span> <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> defined
</code></pre>
<p><strong>Remember:</strong> Restart the Python console by pressing ctrl + d and starting the shell again by using the <code>python3</code> command before testing the code above. The first example has you declare the <code>greet</code> variable in the global scope meaning it will still be available in memory when you run the second example.</p>
<p>As <code>greet</code> is not available globally we get the error that it is not defined.</p>
<h2 id="heading-return-statement">Return Statement:</h2>
<p>Until now our functions are pretty simple. They are receiving data, processing it, and printing them. But in the real world, you need a function to return output so that it can be used in different operations.</p>
<p>To achieve this, return statements are used. Remember, return statements are only part of functions and methods. The syntax for the return statement is quite easy.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add</span>(<span class="hljs-params">a, b</span>):</span>
<span class="hljs-meta">... </span>    <span class="hljs-keyword">return</span> a + b
...
<span class="hljs-meta">&gt;&gt;&gt; </span>add(<span class="hljs-number">1</span>,<span class="hljs-number">3</span>)
<span class="hljs-number">4</span>
</code></pre>
<p>Instead of printing our addition, we are returning the output. The value of the returned output can also be stored in a variable.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>sum = add(<span class="hljs-number">5</span>,<span class="hljs-number">10</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>print(sum)
<span class="hljs-number">15</span>
</code></pre>
<h2 id="heading-lambda-expression">Lambda Expression:</h2>
<p>Consider a situation where you don't want to perform much computation in a function. In such a situation writing a full-fledged function doesn't make sense. To solve this we use a lambda expression or lambda function.</p>
<p>So what is a lambda expression? It is an anonymous function and they are restricted to a single expression. The lambda expression can take n number of arguments.</p>
<p>The syntax for lambda expression is:</p>
<pre><code class="lang-python">variable = <span class="hljs-keyword">lambda</span> arguments: operation
</code></pre>
<p>Let's understand it more by example:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>sum = <span class="hljs-keyword">lambda</span> a: a + <span class="hljs-number">10</span>
</code></pre>
<p>Here we have declared a variable <code>sum</code> which we are using to call the lambda function. <code>a</code> represents the argument that is passed to that function.</p>
<p>Let's call our function:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>x(<span class="hljs-number">5</span>)
<span class="hljs-number">15</span>
</code></pre>
<h2 id="heading-list-comprehension">List comprehension:</h2>
<p>Consider a situation where you want a list of squares. Normally you'll declare a <code>squares</code> list and then in a for loop you'll square out the numbers.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>squares = []
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>):
<span class="hljs-meta">... </span>    squares.append(x**<span class="hljs-number">2</span>)
...
<span class="hljs-meta">&gt;&gt;&gt; </span>squares
[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">9</span>, <span class="hljs-number">16</span>, <span class="hljs-number">25</span>, <span class="hljs-number">36</span>, <span class="hljs-number">49</span>, <span class="hljs-number">64</span>, <span class="hljs-number">81</span>]
</code></pre>
<p>Well this is doable, but we can achieve this in a single line with the help of list comprehension.</p>
<p>There are two ways to achieve this. Let's understand both of them.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>squares = list(map(<span class="hljs-keyword">lambda</span> x: x**<span class="hljs-number">2</span>, range(<span class="hljs-number">10</span>)))
<span class="hljs-meta">&gt;&gt;&gt; </span>squares
[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">9</span>, <span class="hljs-number">16</span>, <span class="hljs-number">25</span>, <span class="hljs-number">36</span>, <span class="hljs-number">49</span>, <span class="hljs-number">64</span>, <span class="hljs-number">81</span>]
</code></pre>
<p>Here we are using <code>list</code> constructor to build a list and inside that lambda function which squares out the number. Another way to achieve the same result is as follows:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>squares = list(x**<span class="hljs-number">2</span> <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>))
<span class="hljs-meta">&gt;&gt;&gt; </span>squares
[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">9</span>, <span class="hljs-number">16</span>, <span class="hljs-number">25</span>, <span class="hljs-number">36</span>, <span class="hljs-number">49</span>, <span class="hljs-number">64</span>, <span class="hljs-number">81</span>]
</code></pre>
<p>I prefer this way because it is easier to more concise and easier to understand.</p>
<p>What about when we have a condition where we want a set of two numbers that are the same? Well, we need to write two for loops and one if loop.</p>
<p>Let's see how that will look:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>num_list = []
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>):
<span class="hljs-meta">... </span>    <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>):
<span class="hljs-meta">... </span>            <span class="hljs-keyword">if</span> i == j:
<span class="hljs-meta">... </span>                    num_list.append((i,j))
...
<span class="hljs-meta">&gt;&gt;&gt; </span>num_list
[(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>), (<span class="hljs-number">1</span>, <span class="hljs-number">1</span>), (<span class="hljs-number">2</span>, <span class="hljs-number">2</span>), (<span class="hljs-number">3</span>, <span class="hljs-number">3</span>), (<span class="hljs-number">4</span>, <span class="hljs-number">4</span>), (<span class="hljs-number">5</span>, <span class="hljs-number">5</span>), (<span class="hljs-number">6</span>, <span class="hljs-number">6</span>), (<span class="hljs-number">7</span>, <span class="hljs-number">7</span>), (<span class="hljs-number">8</span>, <span class="hljs-number">8</span>), (<span class="hljs-number">9</span>, <span class="hljs-number">9</span>)]
</code></pre>
<p>That's a lot of work. And in terms of readability it's hard to understand.</p>
<p>Let's use list comprehension to achieve the same result.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>num_list = list((i,j) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>) <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>) <span class="hljs-keyword">if</span> i == j)

<span class="hljs-meta">&gt;&gt;&gt; </span>num_list
[(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>), (<span class="hljs-number">1</span>, <span class="hljs-number">1</span>), (<span class="hljs-number">2</span>, <span class="hljs-number">2</span>), (<span class="hljs-number">3</span>, <span class="hljs-number">3</span>), (<span class="hljs-number">4</span>, <span class="hljs-number">4</span>), (<span class="hljs-number">5</span>, <span class="hljs-number">5</span>), (<span class="hljs-number">6</span>, <span class="hljs-number">6</span>), (<span class="hljs-number">7</span>, <span class="hljs-number">7</span>), (<span class="hljs-number">8</span>, <span class="hljs-number">8</span>), (<span class="hljs-number">9</span>, <span class="hljs-number">9</span>)]
</code></pre>
<p>See how easy it is to get the same output in a single expression? Well, that's the power of list comprehension.</p>
<h2 id="heading-oop-concepts">OOP concepts:</h2>
<p>Python is a multi-paradigm programming language. It means Python can use different approaches to solve a problem. One of the paradigms is procedural or functional programming. It structures the code like a recipe – a set of steps in the form of functions and code blocks.</p>
<p>Another approach to solving the problem is by creating classes and objects. This is known as object-oriented oriented programming. An object is a collection of data (variables) and methods that act on those data. And classes are a blueprint for each object.</p>
<p>The important thing to understand in object-oriented programming is that objects are at the center of the paradigm – they not only represent the data but also the structure of the program.</p>
<p>You can choose the paradigm that best suits the problem at hand, mix different paradigms in one program, and/or switch from one paradigm to another as your program evolves.</p>
<h3 id="heading-advantages-of-object-oriented-programming">Advantages of object oriented programming</h3>
<ul>
<li><p><strong>Inheritance:</strong> This is one of the most useful concepts in OOP. It specifies that the child object will have all the properties and behavior of the parent object. Thus Inheritance allows us to define a class that inherits all the methods and properties from another class.</p>
</li>
<li><p><strong>Polymorphism:</strong> To understand polymorphism let’s divide the word into two parts. The first part "poly" means many and "morph" means to form or shape. Thus polymorphism means one task can be performed in many different ways.</p>
</li>
</ul>
<p>For example, you have a class <code>animal</code>, and all animals speak. But they speak differently. Here, the “speak” behavior is polymorphic and depends on the animal. So, the abstract “animal” concept does not actually “speak”, but specific animals (like dogs and cats) have a concrete implementation of the action “speak”.</p>
<p>Polymorphism means the same function name or method name being used for different types.</p>
<ul>
<li><strong>Encapsulation:</strong> In object-oriented programming you can restrict access to methods and variables – we can make the methods and variables private. This can prevent the data from being modified by accident and is known as encapsulation.</li>
</ul>
<p>First, we will understand classes, objects, and constructors. Then after that, we will look into the above properties again. If you already know about classes, objects, and constructors, feel free to skip ahead.</p>
<h2 id="heading-classes">Classes:</h2>
<p>There are primitive data structures available in Python, for example, numbers, strings, and lists. These can all be used for simple representations like name, place, cost, and so on.</p>
<p>But what if we have more complex data? If there is a pattern in the repetition of the properties of that data, what can we do?</p>
<p>Suppose we have 100 different animals. Every animal has a name, age, legs, etc. What if we want to add other properties to each animal, or one more animal gets added to that list? To manage such a complex scenario we need classes.</p>
<p>According to the official <a target="_blank" href="https://docs.python.org/3/tutorial/classes.html">Python documentation</a>:</p>
<blockquote>
<p>Classes provide a means of bundling data and functionality together. Creating a new class creates a new type of object, allowing new instances of that type to be made.</p>
</blockquote>
<p>Each class instance can have attributes attached to it for maintaining its state. Class instances can also have methods (defined by its class) for modifying its state.</p>
<p>Syntax of class:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ClassName</span>:</span>

    &lt;expression<span class="hljs-number">-1</span>&gt;
    .
    .
    .
    &lt;expression-N&gt;
</code></pre>
<p>We use <code>class</code> keyword to define a class. We will define a <code>class Car</code>.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>:</span>
    <span class="hljs-keyword">pass</span>
</code></pre>
<h2 id="heading-methods">Methods:</h2>
<p>Methods look the same as functions. The only difference is that methods are dependent on an object. A function can be invoked by name while methods need to be invoked by using their class reference. They are defined inside the class.</p>
<p>In our example, let's create two methods. One is an engine and another is a wheel. These two methods define the parts available in our car.</p>
<p>The below program will give us a better idea of classes:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>:</span>
<span class="hljs-meta">... </span>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">engine</span>(<span class="hljs-params">self</span>):</span>
<span class="hljs-meta">... </span>            print(<span class="hljs-string">"Engine"</span>)
...

<span class="hljs-meta">&gt;&gt;&gt; </span>Car().engine()
Engine
</code></pre>
<p>Here we are calling the <code>engine</code> method by using the <code>Car()</code> reference.</p>
<p>To summarize, the class provides a blueprint of what should be defined but it does not provide any real content. The <code>Car</code> class above defines the engine but it will not state what a specific car’s engine is. It is specified by the object.</p>
<h2 id="heading-objects">Objects:</h2>
<p>The object is an instance of the class. Let’s consider the above example of a car. Here Car is our <code>class</code> and <code>toyota</code> is the <code>object</code> of the car. We can create multiple copies of the object. Every object must be defined using the class.</p>
<p>The syntax for creating an object is:</p>
<pre><code class="lang-python">toyota = Car()
</code></pre>
<p>Let’s consider our <code>Car</code> example to understand objects a bit better:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>:</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">engine</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Engine"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wheel</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Wheel"</span>)

toyota = Car()
</code></pre>
<p>The above <code>toyota = Car()</code> is a <strong>class object</strong>. Class objects support two kinds of operations: attribute references and instantiation.</p>
<p>Class instantiation uses function notation. The instantiation operation (“calling” a class object) creates an empty object.</p>
<p>Now we can call different methods from our class <code>Car</code> using the object <code>toyota</code> that we have created. let’s call the method <code>engine</code> and <code>wheel</code>.</p>
<p>Open your editor and create a file named <code>mycar.py</code>. In that file copy the code below:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>:</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">engine</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Engine"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wheel</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Wheel"</span>)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    toyota = Car()
    toyota.engine()
    toyota.wheel()
</code></pre>
<p>Save the above code. Now let's take a closer look at our program.</p>
<p>Here we are creating a <code>toyota</code> object with the help of <code>Car</code> class. The <code>toyota.engine()</code> is a method object. What exactly happens when a method object is called?</p>
<p>In the call <code>toyota.engine()</code> doesn't take any argument but if you see the method declaration we can see that it takes a <code>self</code> argument.</p>
<p>You may be confused about why it is not throwing an error. Well whenever we use a method object, the call <code>toyota.engine()</code> is converted to <code>Car.engine(toyota)</code>. We will understand more about the self in the upcoming section.</p>
<p>Run the program using the following command.</p>
<pre><code class="lang-shell">python mycar.py
</code></pre>
<p>You'll get the following output:</p>
<pre><code class="lang-shell">Engine
Wheel
</code></pre>
<h2 id="heading-constructor">Constructor:</h2>
<p>The <code>__init__</code> method is the constructor method in Python. The constructor method is used to initialize the data.</p>
<p>Go to the Python shell and enter this example:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>():</span>
<span class="hljs-meta">... </span>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
<span class="hljs-meta">... </span>            print(<span class="hljs-string">"Hello I am the constructor method."</span>)
...
</code></pre>
<p>When we will call our class we will get the following output:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>toyota = Car()
Hello I am the constructor method.
</code></pre>
<p><strong>Note:</strong> You will never have to call the <strong>init</strong>() method – it gets called automatically when you create a class instance.</p>
<h2 id="heading-instance-attributes">Instance attributes:</h2>
<p>All the classes have objects and all the objects have attributes. Attributes are the properties. We use <code>__init__()</code> method to specify an object’s initial attribute.</p>
<p>Let’s consider our car example:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>():</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, model</span>):</span> 
        self.model = model  <span class="hljs-comment">#instance attribute</span>
</code></pre>
<p>In our example, each <code>Car()</code> has a specific model. Thus instance attributes are unique data to each instance.</p>
<h2 id="heading-class-attributes">Class attributes:</h2>
<p>We saw that instance attributes are specific to each object but class attributes are the same for all the instances. Let us look at the example of the car with the help of class attributes.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>():</span>

    no_of_wheels = <span class="hljs-number">4</span> <span class="hljs-comment">#class attribute</span>
</code></pre>
<p>So each car can have different models but all the cars will have only 4 wheels.</p>
<h2 id="heading-self">Self:</h2>
<p>Now let’s understand what <code>self</code> means and how we use it in object-oriented programming. <code>self</code> represents the instance of a class. By using the <code>self</code> keyword we can access the data initialized in the constructor and methods of a class.</p>
<p>Let's look at an example of how <code>self</code> can be used. Let’s create a method named <code>brand</code> under our class <code>Car</code>.</p>
<p>Inside that <code>__init__</code> method, we will pass a model by passing our car’s model name when we are instantiating our object. This name can be accessed anywhere in the class, for example <code>self.model</code> in our case.</p>
<p>Go to the file named <code>mycar.py</code> and replace old code with this code:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>():</span> 

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, model</span>):</span> 
    self.model = model

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">brand</span>(<span class="hljs-params">self</span>):</span> 
    print(<span class="hljs-string">"The brand is"</span>, self.model)  

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
  car = Car(<span class="hljs-string">"Bmw"</span>)
  car.brand()
</code></pre>
<p>Now when we run our above program using the following command:</p>
<pre><code class="lang-shell">python mycar.py
</code></pre>
<p>We will get the following output:</p>
<pre><code class="lang-shell">The brand is Bmw
</code></pre>
<p><strong>Note:</strong> <code>self</code> is a convention and not a real Python keyword. <code>self</code> is an argument in a method and we can use another name in place of it. But it is recommended to use <code>self</code> because it increases the readability of your code.</p>
<h2 id="heading-inheritance">Inheritance:</h2>
<p>Inheritance refers to when a class inherits the property of another class.</p>
<p>The class from which properties are inherited is called the base class. The class which inherits the property of another class is called the derived class.</p>
<p>Inheritance can be defined as a parent and child relationship. The child inherits the properties of the parent. Thus making the child a derived class while parent is a base class. Here the term property refers to attributes and methods.</p>
<p>The syntax for a derived class definition looks like this:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DerivedClassName</span>(<span class="hljs-params">BaseClassName</span>):</span>
    &lt;statement<span class="hljs-number">-1</span>&gt;
    .
    .
    .
    &lt;statement-N&gt;
</code></pre>
<p>It’s important to note that child classes override or extend the attributes and behaviors of parent class methods. This is to say that child classes inherit all of the the attributes and behaviors of their parents – but they're also able to specify different behavior to follow.</p>
<p>The most basic type of class is an object, which generally all other classes inherit as their parent. Let’s modify our previous example to understand how inheritance works.</p>
<p>We will create a base class named <code>vehicle</code>:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Vehicle</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, name</span>):</span>
        self.name = name

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">getName</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.name
</code></pre>
<p>We have created a class <code>Vehicle</code> and instantiated a constructor with <code>self.name</code> which we are using in <code>getName</code> method. Whenever this method will be called, it will return the <code>name</code> that has been passed when an object is instantiated for that class.</p>
<p>Now let’s create a child class <code>Car</code>:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Vehicle</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, name</span>):</span>
        self.name = name

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">getName</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.name

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>(<span class="hljs-params">Vehicle</span>):</span>
  <span class="hljs-keyword">pass</span>
</code></pre>
<p><code>Car</code> is a child class of <code>Vehicle</code>. It inherits all the method and attributes of parent class.</p>
<p>Now let’s use methods and attribute from the <code>Vehicle</code> class in our child class <code>Car</code>.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Vehicle</span>:</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, name, color=<span class="hljs-string">'silver'</span></span>):</span>
        self.name = name
        self.color = color

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_name</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.name

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_color</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.color

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>(<span class="hljs-params">Vehicle</span>):</span>
  <span class="hljs-keyword">pass</span>

audi = Car(<span class="hljs-string">"Audi r8"</span>)
print(<span class="hljs-string">"The name of our car is"</span>, audi.get_name(), <span class="hljs-string">"and color is"</span>, audi.get_color())
</code></pre>
<p>Let's understand what we have done here.</p>
<p>We have declared a class named <code>Vehicle</code> with a constructor that takes name as an argument while color has a default argument.</p>
<p>We have two methods inside it. <code>get_name</code> returns name while <code>get_color</code> returns the color. We have instantiated an object and passed the car name.</p>
<p>One thing you'll notice here that we are using base class methods in our child class declaration.</p>
<p>Run the above program using the following command:</p>
<pre><code class="lang-shell">python mycar.py
</code></pre>
<p>Output:</p>
<pre><code class="lang-python">The name of our car <span class="hljs-keyword">is</span> Audi r8 <span class="hljs-keyword">and</span> color <span class="hljs-keyword">is</span> silver
</code></pre>
<p>We can also override a parent method or attribute. In the above example, we have defined our vehicle color has silver. But what if the color of our car is black?</p>
<p>Now for every child class, we can’t make changes in the parent class. There comes the overriding functionality.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Vehicle</span>:</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, name, color=<span class="hljs-string">'silver'</span></span>):</span>
        self.name = name
        self.color = color

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_name</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.name

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_color</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.color

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>(<span class="hljs-params">Vehicle</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_color</span>(<span class="hljs-params">self</span>):</span>
        self.color = <span class="hljs-string">'black'</span>
        <span class="hljs-keyword">return</span> self.color

audi = Car(<span class="hljs-string">"Audi r8"</span>)
print(<span class="hljs-string">"The name of our car is"</span>, audi.get_name(), <span class="hljs-string">"and color is"</span>, audi.get_color()
</code></pre>
<p>As you can see in the above program, I have not instantiated a constructor. The reason behind this is that our child class <code>Car</code> is only using attributes from the <code>Vehicle</code> class and it is already inheriting them. So in such a scenario, there is no need to re-instantiate these attributes.</p>
<p>Now when we run the above program we will get the following output:</p>
<pre><code class="lang-shell">The name of our car is Audi r8 and color is black
</code></pre>
<h2 id="heading-super">Super:</h2>
<p><code>super()</code> returns a temporary object of the superclass that then allows us to call that superclass’s methods.</p>
<p>Calling the previously built methods with <code>super()</code> saves us from needing to rewrite those methods in our subclass, and allows us to swap out superclasses with minimal code changes. Thus <code>super</code> extends the functionality of the inherited method.</p>
<p>Let’s extend our car example using <code>super()</code>. We will instantiate a constructor with <code>brand_name</code> and <code>color</code> in the parent class, <code>Vehicle</code>. Now we will call this constructor from our child class (<code>Car</code>) using <code>super</code>. We will create a <code>get_description</code> method which is returning <code>self.model</code> from <code>Car</code> class and <code>self.brand_name</code>, <code>self.color</code> from the <code>Vehicle</code> class.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Vehicle</span>:</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand_name, color</span>):</span>
        self.brand_name = brand_name
        self.color = color

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_brand_name</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.brand_name

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>(<span class="hljs-params">Vehicle</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand_name, model, color</span>):</span>  
        super().__init__(brand_name, color)       
        self.model = model

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_description</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Car Name: "</span> + self.get_brand_name() + self.model + <span class="hljs-string">" Color:"</span> + self.color

c = Car(<span class="hljs-string">"Audi "</span>,  <span class="hljs-string">"r8"</span>, <span class="hljs-string">" Red"</span>)
print(<span class="hljs-string">"Car description:"</span>, c.get_description())
print(<span class="hljs-string">"Brand name:"</span>, c.get_brand_name())
</code></pre>
<p>When we run the above program we get following output:</p>
<pre><code class="lang-shell">Car description: Car Name: Audi r8 Color: Red
Brand name: Audi
</code></pre>
<h2 id="heading-multiple-inheritance">Multiple Inheritance:</h2>
<p>When a class inherits the method and attributes from multiple parent class then it is called multiple inheritance. This allows us to use the property from multiple base classes or parent classes in a derived or child class.</p>
<p>The general syntax of multiple Inheritance is as follows:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DerivedClassName</span>(<span class="hljs-params">Base1, Base2, Base3</span>):</span>
    &lt;statement<span class="hljs-number">-1</span>&gt;
    .
    .
    .
    &lt;statement-N&gt;
</code></pre>
<p>Let’s extend our vehicle example using the multiple inheritance property. Here in this example, we will create 3 classes i.e. <code>Vehicle</code>, <code>Cost</code> and <code>Car</code></p>
<p>The classes <code>Vehicle</code> and <code>Cost</code> will be the Parent class. A <code>Vehicle</code> class represents the general property while the <code>Cost</code> class represents its pricing.</p>
<p>As <code>Car</code> has a general property and cost will have two parent classes. Thus we will inherit multiple parent classes.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Vehicle</span>:</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand_name</span>):</span>
        self.brand_name = brand_name

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_brand_name</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.brand_name


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cost</span>:</span>        

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, cost</span>):</span>
        self.cost = cost

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_cost</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.cost


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>(<span class="hljs-params">Vehicle, Cost</span>):</span>    

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand_name, model, cost</span>):</span> 
        self.model = model 
        Vehicle.__init__(self, brand_name) 
        Cost.__init__(self, cost) 

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_description</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.get_brand_name() + self.model + <span class="hljs-string">" is the car "</span> + <span class="hljs-string">"and it's cost is "</span> + self.get_cost()

c = Car(<span class="hljs-string">"Audi "</span>,  <span class="hljs-string">"r8"</span>, <span class="hljs-string">"2 cr"</span>)
print(<span class="hljs-string">"Car description:"</span>, c.get_description())
</code></pre>
<p>Here you will find one thing in the above program that is different from all the other programs in this tutorial. I have used <code>Vehicle.__init__(self, brand_name)</code> in the constructor of <code>Car</code> class. This is one way of calling attributes from the parent class. Another was is <code>super</code> which I have explained above.</p>
<p>When we run the above program we will get the following output:</p>
<pre><code class="lang-python">Car description: Audi r8 <span class="hljs-keyword">is</span> the car <span class="hljs-keyword">and</span> it<span class="hljs-string">'s cost is 2 cr</span>
</code></pre>
<p>Though it can be used effectively, multiple inheritance should be done with care so that our programs do not become ambiguous and difficult for other programmers to understand.</p>
<h2 id="heading-polymorphism">Polymorphism:</h2>
<p>The word polymorphism means having many forms. In programming, polymorphism means same function name (but different signatures) being uses for different types.</p>
<p>Let’s extend our car program using polymorphism. We will create two classes, <code>Car</code> and <code>Bike</code>. Both the classes have common method or function, but they are printing different data. The program is pretty self-explanatory:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>:</span> 

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">company</span>(<span class="hljs-params">self</span>):</span> 
        print(<span class="hljs-string">"Car belongs to Audi company."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">model</span>(<span class="hljs-params">self</span>):</span> 
        print(<span class="hljs-string">"The Model is R8."</span>) 

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">color</span>(<span class="hljs-params">self</span>):</span> 
        print(<span class="hljs-string">"The color is silver."</span>) 

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Bike</span>:</span> 

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">company</span>(<span class="hljs-params">self</span>):</span> 
        print(<span class="hljs-string">"Bike belongs to pulsar company."</span>) 

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">model</span>(<span class="hljs-params">self</span>):</span> 
        print(<span class="hljs-string">"The Model is dominar."</span>) 

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">color</span>(<span class="hljs-params">self</span>):</span> 
        print(<span class="hljs-string">"The color is black."</span>) 

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">func</span>(<span class="hljs-params">obj</span>):</span> 
    obj.company() 
    obj.model() 
    obj.color() 

car = Car() 
bike = Bike() 

func(car) 
func(bike)
</code></pre>
<p>When we run the above code we will get the following output:</p>
<pre><code class="lang-shell">Car belongs to Audi company.
The Model is R8.
The color is silver.
Bike belongs to pulsar company.
The Model is dominar.
The color is black.
</code></pre>
<h2 id="heading-encapsulation">Encapsulation:</h2>
<p>In most object-oriented programming, we can restrict access to methods and variables. This can prevent the data from being modified by accident and is known as encapsulation.</p>
<p>Let’s use encapsulation in our car example. Now imagine we have a super-secret engine. In the first example, we will hide our engine using a <strong>private variable</strong>. In the second example, we will hide our engine using a <strong>private method</strong>.</p>
<p><strong>Example 1:</strong></p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>:</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span> 
    self.brand_name = <span class="hljs-string">'Audi '</span>
    self.model = <span class="hljs-string">'r8'</span>
    self.__engine = <span class="hljs-string">'5.2 L V10'</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_description</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.brand_name + self.model + <span class="hljs-string">" is the car"</span>

c = Car()
print(c.get_description)
print(c.__engine)
</code></pre>
<p>In this example <code>self.__engine</code> is a private attribute. When we run this program we will get the following output.</p>
<pre><code class="lang-shell">Audi r8 is the car
AttributeError: 'Car' object has no attribute '__engine'
</code></pre>
<p>We get an error that <code>Car</code> object doesn't have _engine because it is a private object.</p>
<p><strong>Example 2:</strong></p>
<p>We can also define a private method by adding <code>__</code> in front of the method name. Following is the example of how we can define a private method.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>:</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
      self.brand_name = <span class="hljs-string">'Audi '</span>
      self.model = <span class="hljs-string">'r8'</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__engine</span>(<span class="hljs-params">self</span>):</span>
      <span class="hljs-keyword">return</span> <span class="hljs-string">'5.2 L V10'</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_description</span>(<span class="hljs-params">self</span>):</span>
      <span class="hljs-keyword">return</span> self.brand_name + self.model + <span class="hljs-string">" is the car"</span>


c = Car()
print(c.get_description())
print(c.__engine())
</code></pre>
<p>In this example <code>def __engine(self)</code> is a private method. When we run this program we will get the following output.</p>
<pre><code class="lang-shell">Audi r8 is the car
AttributeError: 'Car' object has no attribute '__engine'
</code></pre>
<p>Now suppose we want to access the private attribute or method we can do it in the following way:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>:</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
      self.brand_name = <span class="hljs-string">'Audi '</span>
      self.model = <span class="hljs-string">'r8'</span>
      self.__engine_name = <span class="hljs-string">'5.2 L V10'</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__engine</span>(<span class="hljs-params">self</span>):</span>
      <span class="hljs-keyword">return</span> <span class="hljs-string">'5.2 L V10'</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_description</span>(<span class="hljs-params">self</span>):</span>
      <span class="hljs-keyword">return</span> self.brand_name + self.model + <span class="hljs-string">" is the car"</span>


c = Car()
print(c.get_description())
print(<span class="hljs-string">"Accessing Private Method: "</span>, c._Car__engine()) 
print(<span class="hljs-string">"Accessing Private variable: "</span>, c._Car__engine_name)
</code></pre>
<p>The output of the following program is:</p>
<pre><code class="lang-shell">Audi r8 is the car
Accessing Private Method:  5.2 L V10
Accessing Private variable:  5.2 L V10
</code></pre>
<p>Encapsulation gives you more control over the degree of coupling in your code. It allows a class to change its implementation without affecting other parts of the code.</p>
<h2 id="heading-decorator">Decorator:</h2>
<p>Imagine you have to extend the functionality of multiple functions. How will you do that?</p>
<p>Well, one way is you can make functional calls and in that function, you can handle it. Making changes in 30 to 40 function calls and remembering where to place the call is a messy task. But the more elegant way provided by Python is with decorators.</p>
<p>What is a decorator? A decorator is a function that takes a function and extends its functionality without modifying it explicitly. Well, I understand if you are still confused about what decorators are. Don't worry – we have a tool named example to explain it.</p>
<p>Let's try an example to understand the decorator. There are two ways to write a decorator.</p>
<h3 id="heading-method-1">Method 1</h3>
<p>We declare a decorator function and in the arguments of the function we expect the function to be passed as an argument. Inside that, we write a wrapper function where operations are carried out and it is returned.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">my_decorator</span>(<span class="hljs-params">func</span>):</span>
<span class="hljs-meta">... </span>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span>():</span>
<span class="hljs-meta">... </span>            print(<span class="hljs-string">"Line Number 1"</span>)
<span class="hljs-meta">... </span>            func()
<span class="hljs-meta">... </span>            print(<span class="hljs-string">"Line Number 3"</span>)
<span class="hljs-meta">... </span>    <span class="hljs-keyword">return</span> wrapper
...
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">say_hello</span>():</span>
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Hello I am line Number 2"</span>)
...
</code></pre>
<p>To call the function we assign the decorator with <code>say_hello</code> as an argument.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>say_hello = my_decorator(say_hello)
</code></pre>
<p>We can also check the reference using <code>say_hello</code>. We will get the output that tells us it has been wrapped by the <code>my_decorator</code> function.</p>
<pre><code class="lang-python">&lt;function my_decorator.&lt;locals&gt;.wrapper at <span class="hljs-number">0x10dc84598</span>&gt;
</code></pre>
<p>Let's call our <code>say_hello</code> function:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>say_hello()
Line Number <span class="hljs-number">1</span>
Hello I am line Number <span class="hljs-number">2</span>
Line Number <span class="hljs-number">3</span>
</code></pre>
<p>See the magic the line "Hello I am line Number 2" gets printed in between Line Number 1 and 3 because the function call gets executed there.</p>
<p>Method 1 is clunky, and because of that many people prefer a different approach.</p>
<h3 id="heading-method-2">Method 2</h3>
<p>Here our decorator declaration remains same but we change how the call is assigned to that decorator. Whichever function requires that decorator wraps itself with <code>@decorator_name</code>.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">my_decorator</span>(<span class="hljs-params">func</span>):</span>
<span class="hljs-meta">... </span>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span>():</span>
<span class="hljs-meta">... </span>            print(<span class="hljs-string">"Line Number 1"</span>)
<span class="hljs-meta">... </span>            func()
<span class="hljs-meta">... </span>            print(<span class="hljs-string">"Line Number 3"</span>)
<span class="hljs-meta">... </span>    <span class="hljs-keyword">return</span> wrapper
...
<span class="hljs-meta">&gt;&gt;&gt; </span>@my_decorator
<span class="hljs-meta">... </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">say_hello</span>():</span>
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Hello I am line Number 2"</span>)
...
<span class="hljs-meta">&gt;&gt;&gt; </span>say_hello()
</code></pre>
<p>Output is the same:</p>
<pre><code class="lang-shell">Line Number 1
Hello I am line Number 2
Line Number 3
</code></pre>
<p>A decorator is a powerful tool and it is used in the following development scenarios of an application:</p>
<ul>
<li><p>Setup logger</p>
</li>
<li><p>Setup configuration</p>
</li>
<li><p>Setup Error catching</p>
</li>
<li><p>Extending common functionality for all function and classes</p>
</li>
</ul>
<h2 id="heading-exceptions">Exceptions:</h2>
<p>When we were learning various syntax we came across various errors. Those errors occurred because of the syntax. But in a real-world application, errors (or commonly known as bugs) not only occur due to syntax issues but also because of network errors or some other cause.</p>
<p>To handle these issues we use Try - Except. In <code>try</code> block, we write the expression that we want to be executed, while in <code>except</code> block we catch the error. The Try-Except block looks as follows:</p>
<pre><code class="lang-python"><span class="hljs-keyword">try</span>:
    expression
<span class="hljs-keyword">except</span>:
    catch error
</code></pre>
<p>Let's understand this by an example:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">try</span>:
<span class="hljs-meta">... </span>    print(value)
<span class="hljs-meta">... </span><span class="hljs-keyword">except</span>:
<span class="hljs-meta">... </span>    print(<span class="hljs-string">"Something went wrong"</span>)
...
</code></pre>
<p>Here we are trying to print the value variable but it is not defined. So we get the following output:</p>
<pre><code class="lang-shell">Something went wrong
</code></pre>
<p>You may be thinking that the line "something went wrong" is not that helpful. So how can we know what went wrong here?</p>
<p>We can print the exception and use it to find out what went wrong. Let's test this in our example:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">try</span>:
<span class="hljs-meta">... </span>    print(value)
<span class="hljs-meta">... </span><span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
<span class="hljs-meta">... </span>    print(e)
...
</code></pre>
<p>And the result is:</p>
<pre><code class="lang-shell">name 'value' is not defined
</code></pre>
<p>Whoa! That's magic. It is notifying me that 'value' is not defined.</p>
<p>Python also provides a tool named <code>raise</code>. Suppose you don't want a certain condition to occur and if it occurs you want to raise it. In such condition you can use <code>raise</code>. Consider the example below:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>i = <span class="hljs-number">5</span>
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">if</span> i &lt; <span class="hljs-number">6</span>:
<span class="hljs-meta">... </span>    <span class="hljs-keyword">raise</span> Exception(<span class="hljs-string">"Number below 6 are not allowed"</span>)
...
</code></pre>
<p>The output we get is as follows:</p>
<pre><code class="lang-shell">Traceback (most recent call last):
  File "&lt;stdin&gt;", line 2, in &lt;module&gt;
Exception: Number below 6 are not allowed
</code></pre>
<p>There are many sub-types of Exceptions, so I recommend that you go through the <a target="_blank" href="https://docs.python.org/3/tutorial/errors.html#errors-and-exceptions">Python Documentation</a> to understand them.</p>
<h2 id="heading-package-import">Package Import:</h2>
<p>You have learned the basics of Python and now you are all ready to build awesome applications. But hold on – we are still missing some important topics.</p>
<p>Without package import, you will be forced to write everything in one single file. Imagine what a mess it will be.</p>
<p>Create two files named <code>main.py</code> and <code>hello.py</code>. Remember both file needs to be in the same directory.</p>
<p>Under <code>hello.py</code> copy paste the following code:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">say_hello</span>():</span>
    print(<span class="hljs-string">"Hello world"</span>)
</code></pre>
<p>Under <code>main.py</code> copy paste the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> hello

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    hello.say_hello()
</code></pre>
<p>In <code>hello.py</code> we have declared a <code>say_hello()</code> function which prints "Hello world". In <code>main.py</code> you'll see an import statement. We are importing the hello module and calling the <code>say_hello()</code> function from that module.</p>
<p>Run our program using the following command:</p>
<pre><code class="lang-shell">➜ python main.py
</code></pre>
<p>Output:</p>
<pre><code class="lang-shell">Hello world
</code></pre>
<p>Now let's understand how to import a module which is in another directory.</p>
<p>Let's create a directory named "data" and move our <code>hello.py</code> inside that directory.</p>
<p>Go to the <code>main.py</code> and change the previous import statement.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> data <span class="hljs-keyword">import</span> hello

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    hello.say_hello()
</code></pre>
<p>There are two ways to import from a directory.</p>
<ul>
<li><p>Method 1: <code>from data import hello</code></p>
</li>
<li><p>Method 2: <code>import data.hello</code></p>
</li>
</ul>
<p>I prefer method 1 because of its readability. You can choose whichever method looks better to you.</p>
<p>Let's run our application using the following command:</p>
<pre><code class="lang-shell">➜ python main.py
</code></pre>
<p>And an error occurs. Wait why did this happen? We did everything right. Let's go through the error:</p>
<pre><code class="lang-shell">Traceback (most recent call last):
  File "main.py", line 1, in &lt;module&gt;
    from data import hello
ImportError: No module named data
</code></pre>
<p>Well Python is telling us that it doesn't recognize a module named data. To solve this issue create a <code>__init__.py</code> inside data directory. Leave the file blank and run the program again and you'll get the following output:</p>
<pre><code class="lang-shell">Hello world
</code></pre>
<p>Well python by default does not treat a directory as a module. To inform Python to treat a directory as a module, <code>__init__.py</code> is required.</p>
<h2 id="heading-json-handling">JSON Handling:</h2>
<p>If you have worked previously with web development or app development you may be aware that all the API calls take place in JSON format. While JSON looks similar to a dictionary in Python, remember that it's very different.</p>
<p>To handle JSON, Python provides an inbuilt <code>json</code> package. To use this package we need to import it as follows:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json
</code></pre>
<p>This library provides two methods which help us in handling the JSON. Let's understand them one by one.</p>
<h3 id="heading-json-loads">JSON loads:</h3>
<p>If you have a JSON string and want to convert it back to a dictionary you need to use the <code>loads</code> method. Go to the Python shell and copy-paste the following code:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">import</span> json
<span class="hljs-meta">&gt;&gt;&gt; </span>json_string = <span class="hljs-string">'{ "user_name":"Sharvin", "age":1000}'</span> <span class="hljs-comment">#JSON String</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>type(json_string)
&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> '<span class="hljs-title">str</span>'&gt;
&gt;&gt;&gt; <span class="hljs-title">data</span> = <span class="hljs-title">json</span>.<span class="hljs-title">loads</span>(<span class="hljs-params">json_string</span>)
&gt;&gt;&gt; <span class="hljs-title">type</span>(<span class="hljs-params">data</span>)
&lt;<span class="hljs-title">class</span> '<span class="hljs-title">dict</span>'&gt;
&gt;&gt;&gt; <span class="hljs-title">data</span>
{'<span class="hljs-title">user_name</span>':</span> <span class="hljs-string">'Sharvin'</span>, <span class="hljs-string">'age'</span>: <span class="hljs-number">1000</span>}
</code></pre>
<h3 id="heading-json-dumps">JSON dumps:</h3>
<p>Now let's convert our data back to the JSON string format using the <code>dumps</code> method.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>jsonString = json.dumps(data)
<span class="hljs-meta">&gt;&gt;&gt; </span>type(jsonString)
&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> '<span class="hljs-title">str</span>'&gt;
&gt;&gt;&gt; <span class="hljs-title">jsonString</span>
'{"<span class="hljs-title">user_name</span>":</span> <span class="hljs-string">"Sharvin"</span>, <span class="hljs-string">"age"</span>: <span class="hljs-number">1000</span>}<span class="hljs-string">'</span>
</code></pre>
<p>To learn more about JSON Manipulation, go through the <a target="_blank" href="https://docs.python.org/3/library/json.html">Python Documentation</a>.</p>
<h2 id="heading-thats-it">That's it!</h2>
<p>And we're done! I hope you now understand the basics of Python. Congratulations! That's a huge achievement.</p>
<p>Feedback is welcomed. Also if you want to learn about any other topic you can tweet the topic name on Twitter and include my Twitter handle. [ <strong>@sharvinshah26</strong> ]</p>
<blockquote>
<p>Feel free to connect with me on <a target="_blank" href="https://twitter.com/sharvinshah26">Twitter</a> and <a target="_blank" href="https://github.com/Sharvin26">Github</a>.</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Flux to Manage State in ReactJS - Explained with an Example ]]>
                </title>
                <description>
                    <![CDATA[ If you have started working on ReactJS recently then you might be wondering how to manage state in React so that your application can scale. To solve this state management issue, many companies and people have developed various solutions. Facebook, w... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-flux-in-react-example/</link>
                <guid isPermaLink="false">66d460f973634435aafcefcc</guid>
                
                    <category>
                        <![CDATA[ Flux ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ State Management  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sharvin Shah ]]>
                </dc:creator>
                <pubDate>Mon, 20 Apr 2020 19:25:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/04/Flux-4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you have started working on ReactJS recently then you might be wondering how to manage state in React so that your application can scale.</p>
<p>To solve this state management issue, many companies and people have developed various solutions. Facebook, who developed ReactJS, came up with a solution called <a target="_blank" href="https://facebook.github.io/flux/"><strong>Flux</strong></a>.</p>
<p>You may have heard about <strong>Redux</strong> if you have worked on front end technology such as <strong>AngularJS</strong> or <strong>EmberJS</strong>. ReactJS also has a library for implementing Redux.</p>
<p>But before learning Redux I would advise you to go through Flux and understand it. After that give Redux a try. I say this because Redux is a more advanced version of Flux. If the concepts of Flux are clear then you can learn redux and integrate it into your application.</p>
<h2 id="heading-what-is-flux">What is flux?</h2>
<p>Flux uses a <strong>unidirectional data flow pattern</strong> to solve state management complexity. Remember it is not a framework – rather it's more of a pattern that targets to solve the state management issue.</p>
<p>Are you wondering what's wrong with the existing MVC framework? Imagine your client's application scales up. You have interaction between many models and views. How would it look?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/Screenshot-2020-04-16-at-6.38.14-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Credit: Image from Facebook F8 Flux Event</em></p>
<p>The relationship between components gets complicated. It becomes hard to scale the application. Facebook faced the same issue. To solve this issue they architected a <strong>Single directional data flow</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/Flux-3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Credit: Image from Facebook's Flux Doc</em></p>
<p>As you can see from the image above, there are a lot of components used in Flux. Let's go through all the components one by one.</p>
<p><strong>View:</strong> this component renders the UI. Whenever any user interaction occurs on it (like an event) then it fires off the action. Also when the Store informs the View that some change has occurred, it re-renders itself. For example, if a user clicks the <strong>Add</strong> button.</p>
<p><strong>Action:</strong> this handles all the events. These events are passed by the view component. This layer is generally used to make API calls. Once the action is done it is dispatched using the Dispatcher. The action can be something like add a post, delete a post, or any other user interaction.</p>
<p>The common structure of the payload for dispatching an event is as follows:</p>
<pre><code class="lang-js">{
    <span class="hljs-attr">actionType</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">title</span>: <span class="hljs-string">"Understanding Flux step by step"</span>,
        <span class="hljs-attr">author</span>: <span class="hljs-string">"Sharvin"</span>
    }
}
</code></pre>
<p>The actionType key is compulsory and it is used by the dispatcher to pass updates to the related store. It is also a known practice to use constants to hold the value name for actionType key so no typos occur. Data holds the event information that we want to dispatch from Action to Store. The name for this key can be anything.</p>
<p><strong>Dispatcher:</strong> this is the central hub and singleton registry. It dispatches the payload from Actions to Store. Also makes sure that there are no cascading effects when an action is dispatched to the store. It ensures that no other action happens before the data layer has completed processing and storing operations.</p>
<p>Consider this component has a traffic controller in the system. It is a centralized list of callbacks. It invokes the callback and broadcasts the payload it received from the action.</p>
<p>Due to this component, the data flow is predictable. Every action updates the specific store with the callback that is registered with the dispatcher.</p>
<p><strong>Store:</strong> this holds the app state and is a data layer of this pattern. Do not consider it as a model from MVC. An application can have one or many app stores. Stores get updated because they have a callback that is registered using the dispatcher.</p>
<p>Node's event emitter is used to update the store and broadcast the update to view. The view never directly updates the application state. It is updated because of the changes to the store.</p>
<p>This is only part of Flux that can update the data. Interfaces implemented in the store are as follows:</p>
<ol>
<li><p>The <strong>EventEmitter</strong> is extended to inform the view that store data has been updated.</p>
</li>
<li><p>Listeners like <strong>addChangeListener</strong> and <strong>removeChangeListener</strong> are added.</p>
</li>
<li><p><strong>emitChange</strong> is used to emit the change.</p>
</li>
</ol>
<p>Consider the above diagram with more stores and views. Still, the pattern and the flow of data will be the same. This is because this is a single direction and predictable data flow, unlike MVC or Two-way binding. This improves the <strong>data consistency</strong> and it's <strong>easier to find the bug</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/Flux-Flow-3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Flux Data Flow</em></p>
<p>Well, Flux brings the following key benefits to the table with the help of <strong>unidirectional data flow:</strong></p>
<ol>
<li><p>The code becomes quite clear and easy to understand.</p>
</li>
<li><p>Easily testable using Unit Test.</p>
</li>
<li><p>Scalable apps can be built.</p>
</li>
<li><p>Predictable data flow.</p>
</li>
</ol>
<blockquote>
<p><strong><em>Note:</em></strong> <em>The only drawback with the Flux is that there is some boilerplate that we need to write. Besides the boilerplate, there is little code we need to write when adding components to the existing application.</em></p>
</blockquote>
<h2 id="heading-application-template">Application Template</h2>
<p>To learn how to implement flux in ReactJS, we will build a Posts page. Here we will display all the posts. The application template is available at this <a target="_blank" href="https://github.com/Sharvin26/DummyBlog/tree/0d56987b2d461b794e7841302c9337eda1ad0725">commit</a>. We will use this as the template for integrating Flux on top of it.</p>
<p>To clone the code from this commit, use the following command:</p>
<pre><code class="lang-shell">git clone  https://github.com/Sharvin26/DummyBlog.git
</code></pre>
<pre><code class="lang-shell">git checkout 0d56987b2d461b794e7841302c9337eda1ad0725
</code></pre>
<p>We will require a <strong>react-router-dom</strong> and <strong>bootstrap</strong> module. To install these packages, use the following command:</p>
<pre><code class="lang-python">npm install react-router-dom@<span class="hljs-number">5.0</span><span class="hljs-number">.0</span> bootstrap@<span class="hljs-number">4.3</span><span class="hljs-number">.1</span>
</code></pre>
<p>Once done you'll see the following application:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/captured.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>DummyBlog</em></p>
<p>To understand Flux in detail we will only implement the <strong>GET</strong> posts page. Once that is done you'll realize the process is the same for <strong>POST</strong>, <strong>EDIT</strong> and <strong>DELETE</strong>.</p>
<p>Here you'll see the following directory structure:</p>
<pre><code class="lang-shell">+-- README.md 
+-- package-lock.json
+-- package.json
+-- node_modules
+-- .gitignore
+-- public
|   +-- index.html
+-- src
|   +-- +-- components
|   +-- +-- +-- common
|   +-- +-- +-- +-- NavBar.js
|   +-- +-- +-- PostLists.js
|    +-- +-- pages
|   +-- +-- +-- Home.js
|   +-- +-- +-- NotFound.js
|   +-- +-- +-- Posts.js
|   +-- index.js
|   +-- App.js
|   +-- db.json
</code></pre>
<blockquote>
<p><strong>Note:</strong> We have added here a <code>db.json</code> file. This is a dummy data file. Since we don't want to build APIs and instead focus on Flux, we will retrieve the data from this file.</p>
</blockquote>
<p>Our Application's base component is <code>index.js</code>. Here we have rendered the <code>App.js</code> inside the <code>index.html</code> under public directory using the <strong>render</strong> and <strong>getElementById</strong> methods. The <code>App.js</code> is used for configuring the routes.</p>
<p>We are also adding <strong>NavBar</strong> component at the top of the other so it will be available for all the components.</p>
<p>Inside the <strong>pages</strong> directory we have 3 files =&gt; <code>Home.js</code>, <code>Posts.js</code>, and <code>NotFound.js</code>. <code>Home.js</code> is simply used to display the Home component. When a user routes to a URL which doesn't exist, then <code>NotFound.js</code> renders.</p>
<p>The <code>Posts.js</code> is the parent component and it is used to get the data from the <code>db.json</code> file. It passes this data to the <code>PostLists.js</code> under the <strong>components</strong> directory. This component is a dumb component and it only handles the UI. It gets the data as props from its parent component (<code>Posts.js</code>) and displays it in the form of cards.</p>
<p>Now that we are clear about how our blog app is working we will start with integrating Flux on top of it.</p>
<h2 id="heading-integrating-flux">Integrating Flux</h2>
<p>Install Flux using the following command:</p>
<pre><code class="lang-shell">npm install flux@3.1.3
</code></pre>
<p>To integrate Flux in our application we will divide this section into 4 subsections:</p>
<ol>
<li><p>Dispatcher</p>
</li>
<li><p>Actions</p>
</li>
<li><p>Stores</p>
</li>
<li><p>View</p>
</li>
</ol>
<p>Note: The complete code is available at this <a target="_blank" href="https://github.com/Sharvin26/DummyBlog">repository</a>.</p>
<h3 id="heading-dispatcher">Dispatcher</h3>
<p>First, create two new folders named <strong>actions</strong> and <strong>stores</strong> under the <strong>src</strong> directory. After that create a file named <code>appDispatcher.js</code> under the same src directory.</p>
<p><strong>Note:</strong> From now all the files which are related to Flux will have <strong>Camel casing</strong> as they are not ReactJS components.</p>
<p>Go to the <code>appDispatcher.js</code> and copy-paste the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { Dispatcher } <span class="hljs-keyword">from</span> <span class="hljs-string">"flux"</span>;
<span class="hljs-keyword">const</span> dispatcher = <span class="hljs-keyword">new</span> Dispatcher();
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> dispatcher;
</code></pre>
<p>Here we are importing the Dispatcher from the flux library that we installed, creating a new object and exporting it so that our actions module can use it.</p>
<h3 id="heading-actions">Actions</h3>
<p>Now go to the <strong>actions</strong> directory and create two files named <code>actionTypes.js</code> and <code>postActions.js</code>. In the <code>actionTypes.js</code> we will define the constants that we require in <code>postActions.js</code> and store module.</p>
<p>The reason behind defining constants is that we don't want to make typos. You don't have to define constants but it is generally considered a good practice.</p>
<pre><code class="lang-js"><span class="hljs-comment">// actionTypes.js</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">GET_POSTS</span>: <span class="hljs-string">"GET_POSTS"</span>,
};
</code></pre>
<p>Now inside the <code>postActions.js</code>, we will retrieve the data from <code>db.json</code> and use the dispatcher object to dispatch it.</p>
<pre><code class="lang-js"><span class="hljs-comment">//postActions.js</span>

<span class="hljs-keyword">import</span> dispatcher <span class="hljs-keyword">from</span> <span class="hljs-string">"../appDispatcher"</span>;
<span class="hljs-keyword">import</span> actionTypes <span class="hljs-keyword">from</span> <span class="hljs-string">"./actionTypes"</span>;
<span class="hljs-keyword">import</span> data <span class="hljs-keyword">from</span> <span class="hljs-string">"../db.json"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPosts</span>(<span class="hljs-params"></span>) </span>{
    dispatcher.dispatch({
        <span class="hljs-attr">actionTypes</span>: actionTypes.GET_POSTS,
        <span class="hljs-attr">posts</span>: data[<span class="hljs-string">"posts"</span>],
    });
}
</code></pre>
<p>Here in the above code, we have imported the dispatcher object, actionTypes constant, and data. We are using a dispatcher object's dispatch method to send the data to the store. The data in our case will be sent in the following format:</p>
<pre><code class="lang-json">{
    actionTypes: <span class="hljs-string">"GET_POSTS"</span>,
    posts: [
        {
            <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
            <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Hello World"</span>,
            <span class="hljs-attr">"author"</span>: <span class="hljs-string">"Sharvin Shah"</span>,
            <span class="hljs-attr">"body"</span>: <span class="hljs-string">"Example of blog application"</span>
        },
        {
            <span class="hljs-attr">"id"</span>: <span class="hljs-number">2</span>,
            <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Hello Again"</span>,
            <span class="hljs-attr">"author"</span>: <span class="hljs-string">"John Doe"</span>,
            <span class="hljs-attr">"body"</span>: <span class="hljs-string">"Testing another component"</span>
        }
    ]
}
</code></pre>
<h3 id="heading-stores">Stores</h3>
<p>Now we need to build the store which will act as a <strong>data layer</strong> for storing the posts. It will have an <strong>event listener</strong> to inform the view that something has changed, and will <strong>register</strong> using dispatcher with the actions to get the data.</p>
<p>Go to the store directory and create a new file called <code>postStore.js</code>. Now first, we will import <strong>EventEmitter</strong> from the Events package. It is available in the NodeJS by default. We will also import the dispatcher object and actionTypes constant file here.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { EventEmitter } <span class="hljs-keyword">from</span> <span class="hljs-string">"events"</span>;
<span class="hljs-keyword">import</span> dispatcher <span class="hljs-keyword">from</span> <span class="hljs-string">"../appDispatcher"</span>;
<span class="hljs-keyword">import</span> actionTypes <span class="hljs-keyword">from</span> <span class="hljs-string">"../actions/actionTypes"</span>;
</code></pre>
<p>We will declare the constant of the <strong>change</strong> event and a variable to hold the posts whenever the dispatcher passes it.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> CHANGE_EVENT = <span class="hljs-string">"change"</span>;
<span class="hljs-keyword">let</span> _posts = [];
</code></pre>
<p>Now we will write a class that extends the <strong>EventEmitter</strong> as its base class. We will declare the following methods in this class:</p>
<p><code>addChangeListener</code>: It uses the NodeJS <strong>EventEmitter.on</strong>. It adds a change listener that accepts the callback function.</p>
<p><code>removeChangeListener</code>: It uses the NodeJS <strong>EventEmitter.removeListener*</strong>.* Whenever we don't want to listen for a specific event we use the following method.</p>
<p><code>emitChange</code>: It uses the NodeJS <strong>EventEmitter.emit*</strong>.* Whenever any change occurs, it emits that change.</p>
<p>This class will also have a method called <code>getPosts</code> which returns the variable <code>_posts</code> that we have declared above the class.</p>
<p>Below the variable declaration add the following code:</p>
<pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostStore</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">EventEmitter</span> </span>{
    addChangeListener(callback) {
        <span class="hljs-built_in">this</span>.on(CHANGE_EVENT, callback);
    }

    removeChangeListener(callback) {
        <span class="hljs-built_in">this</span>.removeListener(CHANGE_EVENT, callback);
    }

    emitChange() {
        <span class="hljs-built_in">this</span>.emit(CHANGE_EVENT);
    }

    getPosts() {
        <span class="hljs-keyword">return</span> _posts;
    }
}
</code></pre>
<p>Now create the <code>store</code> object of our PostStore class. We will export this object so that we can use it in the view.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> store = <span class="hljs-keyword">new</span> PostStore();
</code></pre>
<p>After that, we will use the dispatcher's <strong>register</strong> method to receive the payload from our Actions component.</p>
<p>To register for the specific event, we need to use the <code>actionTypes</code> value and determine which action has occurred and process the data accordingly. Add the following code below the object declaration:</p>
<pre><code class="lang-js">dispatcher.register(<span class="hljs-function">(<span class="hljs-params">action</span>) =&gt;</span> {
    <span class="hljs-keyword">switch</span> (action.actionTypes) {
        <span class="hljs-keyword">case</span> actionTypes.GET_POSTS:
            _posts = action.posts;
            store.emitChange();
            <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">default</span>:
    }
});
</code></pre>
<p>We will export the object from this module so others can use it.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> store;
</code></pre>
<h3 id="heading-view">View</h3>
<p>Now we will update our view to send the event to <code>postActions</code> whenever our Posts page is loaded and receive the payload from the postStore. Go to <code>Posts.js</code> under the <strong>pages</strong> directory. You'll find the following code inside the <strong>useEffect</strong> method:</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
    setposts(data[<span class="hljs-string">"posts"</span>]);
}, []);
</code></pre>
<p>We will change how our useEffect reads and updates the data. First, we will use the <code>addChangeListener</code> method from the postStore class and we will pass an <code>onChange</code> callback to it. We will set the <code>posts</code> state value to have a return value of the <code>getPosts</code> method from the <code>postStore.js</code> file.</p>
<p>At the start, the store will return an empty array as there is no data available. So we will call a <code>_getPosts_</code> method from the <code>postActions.js</code>. This method will read the data and pass it to the store. Then the store will emit the change and <code>addChangeListener</code> will listen to the change and update the value of the <code>posts</code> in its <code>onChange</code> callback.</p>
<p>If this seems confusing don't worry – check out the flow chart below which makes it easier to understand.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/FluxBlogFlow-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Remove the old code and update the following code inside <code>Posts.js</code>:</p>
<pre><code class="lang-js"><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> PostLists <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/PostLists"</span>;
<span class="hljs-keyword">import</span> postStore <span class="hljs-keyword">from</span> <span class="hljs-string">"../stores/postStore"</span>;
<span class="hljs-keyword">import</span> { getPosts } <span class="hljs-keyword">from</span> <span class="hljs-string">"../actions/postActions"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PostPage</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [posts, setPosts] = useState(postStore.getPosts());

    useEffect(<span class="hljs-function">() =&gt;</span> {
        postStore.addChangeListener(onChange);
        <span class="hljs-keyword">if</span> (postStore.getPosts().length === <span class="hljs-number">0</span>) getPosts();
        <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> postStore.removeChangeListener(onChange);
    }, []);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onChange</span>(<span class="hljs-params"></span>) </span>{
        setPosts(postStore.getPosts());
    }

    <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">PostLists</span> <span class="hljs-attr">posts</span>=<span class="hljs-string">{posts}</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> PostPage;
</code></pre>
<p>Here you'll find that we have also removed the import and also we are using <code>setPosts</code> inside our callback instead of useEffect method. The <code>return () =&gt; postStore.removeChangeListener(onChange);</code> is used to remove the listener once the user leaves that page.</p>
<p>With this go to the Blog Page and you'll find that our blog app is working. The only difference is that now instead of reading the data in the <strong>useEffect</strong> method we are reading it in actions, storing it in the store, and sending it to the components that require it.</p>
<p>When using the actual API you'll find that the application loads the data from the API one time and stores it in the store. When we revisit the same page you'll observe that no API call is required again. You can monitor it under the source tab in Chrome Developer console.</p>
<p>And we're done!! I hope this tutorial has made the idea of Flux clearer and you'll be able to use it in your projects.</p>
<blockquote>
<p>Feel free to connect with me on <a target="_blank" href="https://twitter.com/sharvinshah26">Twitter</a> and <a target="_blank" href="https://github.com/Sharvin26">Github</a>.</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a TodoApp using ReactJS and Firebase ]]>
                </title>
                <description>
                    <![CDATA[ Hello folks, welcome to this tutorial. Before we begin you should be familiar with basic ReactJS concepts. If you're not, I would recommend that you go through the ReactJS documentation. We will use the following components in this application: Reac... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-todo-application-using-reactjs-and-firebase/</link>
                <guid isPermaLink="false">66d460f47df3a1f32ee7f897</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Firebase ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sharvin Shah ]]>
                </dc:creator>
                <pubDate>Wed, 15 Apr 2020 00:01:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/04/Screenshot-2020-04-11-at-5.10.03-PM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hello folks, welcome to this tutorial. Before we begin you should be familiar with basic ReactJS concepts. If you're not, I would recommend that you go through the <a target="_blank" href="https://reactjs.org/docs/getting-started.html">ReactJS documentation</a>.</p>
<p>We will use the following components in this application:</p>
<ol>
<li><p><a target="_blank" href="https://reactjs.org/"><strong>ReactJS</strong></a></p>
</li>
<li><p><a target="_blank" href="https://material-ui.com/"><strong>Material UI</strong></a></p>
</li>
<li><p><a target="_blank" href="https://firebase.google.com/"><strong>Firebase</strong></a></p>
</li>
<li><p><a target="_blank" href="https://expressjs.com/"><strong>ExpressJS</strong></a></p>
</li>
<li><p><a target="_blank" href="https://www.postman.com/"><strong>Postman</strong></a></p>
</li>
</ol>
<h2 id="heading-how-our-application-is-going-to-look">How our application is going to look:</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/Account-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Account creation</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/ezgif.com-optimize.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>TodoApp Dashboard</em></p>
<hr>
<h2 id="heading-application-architecture">Application Architecture:</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/TodoApp-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Application Architecture</em></p>
<h2 id="heading-understanding-our-components">Understanding our components:</h2>
<p>You may be wondering why we are using firebase in this application. Well, it provides secure <strong>Authentication</strong>, a <strong>Real-time database</strong>, a <strong>Serverless Component,</strong> and a <strong>Storage bucket</strong>.</p>
<p>We are using Express here so that we don't need to handle HTTP Exceptions. We are going to use all the firebase packages in our functions component. This is because we don't want to make our client application too big, which tends to slow the loading process of the UI.</p>
<p><strong>Note:</strong> I am going to divide this tutorial into four separate sections. At the start of every section, you will find a git commit that has the code developed in that section. Also If you want to see the complete code then it is available in this <a target="_blank" href="https://github.com/Sharvin26/TodoApp">repository</a>.</p>
<h2 id="heading-section-1-developing-todo-apis">Section 1: Developing Todo APIs</h2>
<p>In this section**,** we are going to develop these elements:</p>
<ol>
<li><p><strong>Configure the firebase functions.</strong></p>
</li>
<li><p><strong>Install the Express framework and build Todo APIs.</strong></p>
</li>
<li><p><strong>Configuring firestore as database.</strong></p>
</li>
</ol>
<p>The <strong>Todo API code</strong> implemented in this section can be found at this <a target="_blank" href="https://github.com/Sharvin26/TodoApp/tree/256e69f5d53646b648347b6f1fbdb965ad184763">commit</a>.</p>
<h3 id="heading-configure-firebase-functions">Configure Firebase Functions:</h3>
<p>Go to the <a target="_blank" href="https://firebase.google.com/">Firebase console</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/FirebaseFunctions.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Firebase Console</em></p>
<p>Select the <strong>Add Project</strong> option. After that follow the gif down below step by step to configure the firebase project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/FirebaseConfigure.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Firebase Configuration</em></p>
<p>Go to the functions tab and click on the <strong>Get Started</strong> button:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/FirebaseFunctionConfig1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Functions Dashboard</em></p>
<p>You will see a dialogue box which has instructions on <strong>How to set up the Firebase Functions</strong>. Go to your local environment. Open a command-line tool. To install the firebase tools in your machine use the command below:</p>
<pre><code class="lang-shell"> npm install -g firebase-tools
</code></pre>
<p>Once that is done then use the command <code>firebase init</code> to configure the firebase functions in your local environment. Select the following options when initialising the firebase function in the local environment:</p>
<ol>
<li><p>Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your choices =&gt; <em>Functions: Configure and deploy Cloud Functions</em></p>
</li>
<li><p>First, let’s associate this project directory with a Firebase project …. <em>\=&gt; Use an existing project</em></p>
</li>
<li><p>Select a default Firebase project for this directory =&gt; <em>application_name</em></p>
</li>
<li><p>What language would you like to use to write Cloud Functions? =&gt; <em>JavaScript</em></p>
</li>
<li><p>Do you want to use ESLint to catch probable bugs and enforce style? =&gt; <em>N</em></p>
</li>
<li><p>Do you want to install dependencies with npm now? (Y/n) =&gt; <em>Y</em></p>
</li>
</ol>
<p>After the configuration is done you will get the following message:</p>
<pre><code class="lang-shell">✔ Firebase initialization complete!
</code></pre>
<p>This will be our directory structure once the initialization is completed:</p>
<pre><code class="lang-shell">+-- firebase.json 
+-- functions
|   +-- index.js
|   +-- node_modules
|   +-- package-lock.json
|   +-- package.json
</code></pre>
<p>Now open the <code>index.js</code> under functions directory and copy-paste the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> functions = <span class="hljs-built_in">require</span>(<span class="hljs-string">'firebase-functions'</span>);

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

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

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

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

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

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

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

admin.initializeApp();

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

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

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

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

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

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

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

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

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

METHOD: POST

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

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

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

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

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

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

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

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

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

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

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

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

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

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

firebase.initializeApp(config);

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

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

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

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

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

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

METHOD: POST

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

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

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

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

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

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

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

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

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

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

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

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

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

METHOD: POST

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

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

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

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

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

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

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

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

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

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

METHOD: GET

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

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

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

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

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

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

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

METHOD: POST

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">MuiThemeProvider</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span>&gt;</span>
        // Router and switch will be here.
        <span class="hljs-tag">&lt;/<span class="hljs-name">MuiThemeProvider</span>&gt;</span></span>
    );
}
</code></pre>
<p>We missed applying a theme to our button in <code>todo.js</code> in the <code>CardActions</code> . Add the color tag for the view, edit, and delete button.</p>
<pre><code class="lang-js">&lt;Button size=<span class="hljs-string">"small"</span> color=<span class="hljs-string">"primary"</span> ...&gt;
</code></pre>
<p>Go to the browser and you will find that everything is the same except that the app is a different color.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/FinalTodo.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>TodoApp after applying theme</em></p>
<p>And we're done! We have built a TodoApp using ReactJS and Firebase. If you have built it all the way to this point then a very big congratulations to you on this achievement.</p>
<blockquote>
<p>Feel free to connect with me on <a target="_blank" href="https://twitter.com/sharvinshah26">Twitter</a> and <a target="_blank" href="https://github.com/Sharvin26">Github</a>.</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
