<?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" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Shahed Nasser]]></title><description><![CDATA[No Description]]></description><link>https://blog.shahednasser.com/</link><image><url>https://blog.shahednasser.com/favicon.png</url><title>Shahed Nasser</title><link>https://blog.shahednasser.com/</link></image><generator>Jamify 1.0</generator><lastBuildDate>Wed, 11 Jan 2023 20:37:12 GMT</lastBuildDate><atom:link href="https://blog.shahednasser.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[How to Create a Python Discord Bot For Data Analysis]]></title><description><![CDATA[In this article, we are going to create our own bot using Python.]]></description><link>https://blog.shahednasser.com/how-to-create-a-python-discord-bot-for-data-analysis/</link><guid isPermaLink="false">Ghost__Post__63bf1a5045c6d805f7d9da8b</guid><category><![CDATA[Python]]></category><dc:creator><![CDATA[Manthan Koolwal]]></dc:creator><pubDate>Wed, 11 Jan 2023 20:35:06 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/5bc67e2026a65955ceca32b52fb52581/discord-bot-python.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/5bc67e2026a65955ceca32b52fb52581/discord-bot-python.jpg" alt="How to Create a Python Discord Bot For Data Analysis"/><p>Chatrooms have become very vital for course distribution, gaming, crypto lovers, etc. <a href="https://discord.com/">Discord</a> covers all this by offering dedicated chatrooms for every industry.</p><p>But what if you want to create your own discord bot?</p><p>In this article, we are going to create our own bot using <a href="https://www.python.org/">Python</a>.</p><h2 id="what-is-discord">What is Discord?</h2><p>Discord is a popular platform for online communities, and it’s important to have automated processes in place to manage the community effectively. One way to do this is to use “bot users” which are automated programs that can respond to events and commands on Discord as if they were real users.</p><p>For example, if you manage a Discord guild and want to welcome new members, you can use a bot to automatically send them a message. As the community grows, it may become impractical to welcome each new member personally, but a bot can handle this task for you, allowing you to customize its behavior and control how it interacts with users.</p><h2 id="what-is-a-bot"><strong>What is a bot?</strong></h2><p>A bot is a type of software application or script that performs automated tasks on the internet. In the context of Discord, a bot is a type of user account that can be added to a Discord server and controlled through commands. Discord bots are typically used to perform a variety of tasks, such as welcoming new members, moderating conversations, and responding to user requests. Discord bots can be programmed to do a wide range of things, and they are often used to add additional functionality to a server.</p><h2 id="why-use-python-to-create-discord-bot"><strong>Why Use Python to Create Discord Bot?</strong></h2><p>Python is a general-purpose programming language that can be used to build almost anything. Some common use cases of Python include web development, data science, scientific computing, Automation like <a href="https://www.scrapingdog.com/blog/what-is-web-scraping/">web scraping</a>, designing desktop applications, and games, and many more.</p><p>With endless possibilities and applications, Python would be a go to language for creating a discord bot.</p><p>Other reasons why you might choose to use Python for creating a Discord bot:</p><ol><li><strong>Python is a popular</strong>, versatile programming language. It has a large and active community, which means there are many libraries and frameworks available that can make it easier to build a Discord bot.<br/></li><li><strong>Python is easy to learn and use</strong>. Its syntax is straightforward and readable, so it's a good language to start with if you're new to programming.<br/></li><li><strong>Python has strong support</strong> for interacting with Discord's API. There are several libraries available that make it easy to write a Discord bot in Python, such as discord.py, which is the most widely used library for building Discord bots in Python.<br/></li><li><strong>Python is fast to prototype and develop with.</strong> Its simplicity and flexibility make it a great choice for rapid development, so you can build and deploy your Discord bot quickly.</li></ol><h2 id="how-to-create-a-discord-bot-using-python">How to create a Discord bot using Python?</h2><p>Using the <a href="https://pypi.org/project/discord.py/">Discord Python library</a>, you can easily create a bot that can perform a variety of tasks, such as sending messages, moderating conversations, and more. </p><p>You can customize your bot to perform data analysis tasks by using various Python libraries, such as NumPy, Pandas, and Matplotlib.</p><h3 id="prerequisites">Prerequisites</h3><p>To get started, you’ll need to have Python 3.x installed on your machine and set up a Discord account, and create a new Discord bot. </p><p>You can then use the Discord Python library and the <code class="language-text">discord.py</code> module to interact with the Discord API and create your bot.</p><h2 id="installation"><strong>Installation</strong><br/></h2><p>I am assuming you have already installed Python on your machine. Then, install the Discord Python library, called <code class="language-text">discord.py</code>, using pip.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">pip <span class="token function">install</span> discord.py</code></pre></div><p>After this create your python file where you will write the code and import all the libraries.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py"><span class="token keyword">import</span> discord <span class="token keyword">from</span> discord<span class="token punctuation">.</span>ext <span class="token keyword">import</span> commands</code></pre></div><p>Then we have to create a new Discord client and assign it to a variable.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py">client <span class="token operator">=</span> commands<span class="token punctuation">.</span>Bot<span class="token punctuation">(</span>command_prefix <span class="token operator">=</span> <span class="token string">'.'</span><span class="token punctuation">)</span></code></pre></div><p>Then define a function that will be called when the bot is ready to go online.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py"><span class="token decorator annotation punctuation">@client<span class="token punctuation">.</span>event</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">on_ready</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'Bot is ready!'</span><span class="token punctuation">)</span></code></pre></div><p>The next step is to use the <code class="language-text">@client.command()</code> decorator to define a function that will be called when a certain command is received.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py"><span class="token decorator annotation punctuation">@client<span class="token punctuation">.</span>command</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">greet</span><span class="token punctuation">(</span>ctx<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">await</span> ctx<span class="token punctuation">.</span>send<span class="token punctuation">(</span><span class="token string">'Hello!'</span><span class="token punctuation">)</span></code></pre></div><p>Finally, run the bot using the <code class="language-text">run()</code> method, passing in your Discord bot's token.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py">client<span class="token punctuation">.</span>run<span class="token punctuation">(</span><span class="token string">'YOUR_BOT_TOKEN_HERE'</span><span class="token punctuation">)</span></code></pre></div><p>This is just a basic outline of how you can create a Discord bot in Python.</p><h3 id="how-to-interact-with-discord-apis-using-python">How to interact with discord APIs using python?</h3><p>To interact with Discord APIs using Python, you will need to use a Python library that provides access to the APIs. There are several libraries available for interacting with the Discord API, including:</p><ol><li><code class="language-text">discord.py</code>: This is an official library developed and maintained by the Discord team. It provides a simple, asyncio-based interface for interacting with the Discord API.</li><li><code class="language-text">discord.py-rewrite</code>: This is a rewrite of discord.py that uses a more modern syntax and includes additional features such as support for WebSockets.</li></ol><p>Once you have installed the library, you will need to import it into your Python script and use the provided functions and classes to interact with the Discord API.</p><p>Here is an example of how you might use the discord.py library to send a message to a Discord channel.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py"><span class="token keyword">import</span> discord client <span class="token operator">=</span> discord<span class="token punctuation">.</span>Client<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@client<span class="token punctuation">.</span>event</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">on_ready</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'Logged in as'</span><span class="token punctuation">)</span> <span class="token keyword">print</span><span class="token punctuation">(</span>client<span class="token punctuation">.</span>user<span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token keyword">print</span><span class="token punctuation">(</span>client<span class="token punctuation">.</span>user<span class="token punctuation">.</span><span class="token builtin">id</span><span class="token punctuation">)</span> <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'------'</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@client<span class="token punctuation">.</span>event</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">on_message</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">if</span> message<span class="token punctuation">.</span>content<span class="token punctuation">.</span>startswith<span class="token punctuation">(</span><span class="token string">'!hello'</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">await</span> message<span class="token punctuation">.</span>channel<span class="token punctuation">.</span>send<span class="token punctuation">(</span><span class="token string">'Hello!'</span><span class="token punctuation">)</span> client<span class="token punctuation">.</span>run<span class="token punctuation">(</span><span class="token string">'your_bot_token'</span><span class="token punctuation">)</span> </code></pre></div><p>This script will create a Discord bot that responds to the command “!hello” by sending the message “Hello!” to the channel. You will need to replace <code class="language-text">your_bot_token</code> with the actual token for your bot, which you can get from the Discord Developer Portal.</p><h2 id="getting-data-for-the-bot-for-data-analysis">Getting data for the bot for data analysis</h2><p>It is possible to create a Discord bot in Python that can perform data analysis tasks. Here is an example of how you might use the discord.py library to create a bot that retrieves data from an API and performs some basic analysis on it.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py"><span class="token keyword">import</span> discord <span class="token keyword">import</span> requests <span class="token keyword">import</span> pandas <span class="token keyword">as</span> pd client <span class="token operator">=</span> discord<span class="token punctuation">.</span>Client<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@client<span class="token punctuation">.</span>event</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">on_message</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">if</span> message<span class="token punctuation">.</span>content<span class="token punctuation">.</span>startswith<span class="token punctuation">(</span><span class="token string">'!data'</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token comment"># Retrieve data from API</span> data <span class="token operator">=</span> requests<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'https://api.example.com/data'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>json<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># Convert data to a Pandas DataFrame</span> df <span class="token operator">=</span> pd<span class="token punctuation">.</span>DataFrame<span class="token punctuation">(</span>data<span class="token punctuation">)</span> <span class="token comment"># Perform some basic analysis on the data</span> mean <span class="token operator">=</span> df<span class="token punctuation">[</span><span class="token string">'value'</span><span class="token punctuation">]</span><span class="token punctuation">.</span>mean<span class="token punctuation">(</span><span class="token punctuation">)</span> median <span class="token operator">=</span> df<span class="token punctuation">[</span><span class="token string">'value'</span><span class="token punctuation">]</span><span class="token punctuation">.</span>median<span class="token punctuation">(</span><span class="token punctuation">)</span> std <span class="token operator">=</span> df<span class="token punctuation">[</span><span class="token string">'value'</span><span class="token punctuation">]</span><span class="token punctuation">.</span>std<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># Send results back to Discord</span> <span class="token keyword">await</span> message<span class="token punctuation">.</span>channel<span class="token punctuation">.</span>send<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f'Mean: </span><span class="token interpolation"><span class="token punctuation">{</span>mean<span class="token punctuation">:</span><span class="token format-spec">.2f</span><span class="token punctuation">}</span></span><span class="token string">'</span></span><span class="token punctuation">)</span> <span class="token keyword">await</span> message<span class="token punctuation">.</span>channel<span class="token punctuation">.</span>send<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f'Median: </span><span class="token interpolation"><span class="token punctuation">{</span>median<span class="token punctuation">:</span><span class="token format-spec">.2f</span><span class="token punctuation">}</span></span><span class="token string">'</span></span><span class="token punctuation">)</span> <span class="token keyword">await</span> message<span class="token punctuation">.</span>channel<span class="token punctuation">.</span>send<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f'Standard Deviation: </span><span class="token interpolation"><span class="token punctuation">{</span>std<span class="token punctuation">:</span><span class="token format-spec">.2f</span><span class="token punctuation">}</span></span><span class="token string">'</span></span><span class="token punctuation">)</span> client<span class="token punctuation">.</span>run<span class="token punctuation">(</span><span class="token string">'your_bot_token'</span><span class="token punctuation">)</span></code></pre></div><p>This script will create a bot that listens for the command “!data” and responds by retrieving data from an API, converting it to a Pandas DataFrame, and performing some basic statistical analysis on it. The results of the analysis are then sent back to the Discord channel as a message. You will need to replace <code class="language-text">https://api.example.com/data</code> with the actual URL of the API you want to use and <code class="language-text">your_bot_token</code> with the actual token for your bot.</p><p>You can customize this script to perform a variety of data analysis tasks, depending on the needs of your application. For example, you could use this approach to create a bot that retrieves and analyzes data from financial markets, social media, or any other source of data that has an API available.</p><h2 id="conclusion">Conclusion</h2><p>In this tutorial, you learned how to create a Discord bot using <strong>Python and the discord.py library</strong>. You learned the basics of setting up a bot, handling events, and using commands and checks. You can use this knowledge to build bots for interacting with users on Discord servers that you manage or even on servers managed by other users.</p><p>You can also use the discord.py library to take your bots to the next level and build more advanced functionality. In addition to the discord.py library, you can also explore other tools such as ChatterBot, Tweepy, InstaPy, and Alexa Skills to learn how to create bots for different platforms using Python.</p>]]></content:encoded></item><item><title><![CDATA[How to Lint Code and Prose in Documentation]]></title><description><![CDATA[This article covers the different methods and ways you can lint prose or content and code blocks to ensure it follows your style guide.]]></description><link>https://blog.shahednasser.com/how-to-lint-code-and-prose-in-documentation/</link><guid isPermaLink="false">Ghost__Post__63af16954e918d05f3537d41</guid><category><![CDATA[Documentation]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Fri, 30 Dec 2022 17:48:59 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/153e2196d17bba6f3f3a8b18a85b57cf/lint-prose-code.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/153e2196d17bba6f3f3a8b18a85b57cf/lint-prose-code.jpg" alt="How to Lint Code and Prose in Documentation"/><p>An essential part of the documentation is being consistent. You must be consistent with how you write and present your documents and the information in them.</p><p>This includes both the written content and the code blocks. Your documentation should follow a style guide that keeps your content across pages consistent.</p><p>However, ensuring that your content follows the style guide manually is difficult. You might easily miss small mistakes here and there. This is especially the case when your documentation is open source, where contributors can make fixes or changes to it.</p><p>This article covers the different methods and ways you can lint prose or content and code blocks to ensure it follows your style guide.</p><h2 id="why-use-a-style-guide">Why Use a Style Guide?</h2><p>Documentation should provide a great developer experience. This includes consistency, clarity, and technical accuracy.</p><p>Creating a style guide can provide your documentation with the following benefits:</p><ul><li>Your tone remains consistent. For example, you shouldn't change between using "you" and "we". You should decide on the tone you want to speak to the developer with and stick to it.</li><li>You ensure your content is outlined the same across pages. If you use dividers between sections, you should do that across the documentation. Switching between using and not using them can confuse the reader on when a section starts and ends.</li><li>You maintain content that is written for everyone. Your tone shouldn't be biased toward gender, development level, disabilities, or anything similar.</li></ul><p>Although style guides generally refer to the content of the documentation, you should also maintain a set of rules for your code block.</p><p>For example, if you're using JavaScript make sure you either use or don't use semicolons consistently. Similarly, make sure you either use double quotes across the code blocks or single quotes.</p><h2 id="markdown-content">Markdown Content</h2><p>Most documentation is written in <a href="https://www.markdownguide.org/getting-started/">Markdown</a> (MD) or <a href="https://mdxjs.com/docs/">MDX</a> formats. So, this article specifically targets linting markdown files.</p><p>If you write your documentation in different file formats, these solutions might not work for you.</p><h2 id="lint-prose-with-vale">Lint Prose with Vale</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/12/Screenshot-2022-12-30-at-7.22.48-PM.png" class="kg-image" alt="How to Lint Code and Prose in Documentation" loading="lazy" width="2000" height="980" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/12/Screenshot-2022-12-30-at-7.22.48-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/12/Screenshot-2022-12-30-at-7.22.48-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/12/Screenshot-2022-12-30-at-7.22.48-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2022/12/Screenshot-2022-12-30-at-7.22.48-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://vale.sh/">Vale</a> is a linter for prose or content. It allows you to define rules based on your style guide, then shows you errors, warnings, or suggestions for changes in your documentation.</p><p>So many projects and companies use Vale, including <a href="https://github.com/github/codeql/blob/main/docs/codeql/.vale.ini">GitHub</a>, <a href="https://github.com/microsoft/spring-cloud-azure/blob/main/docs/.vale.ini">Microsoft</a>, <a href="https://github.com/angular/angular/tree/main/aio/tools/doc-linter">Angular</a>, and more.</p><p>Vale provides some ready-made styles and packages that you can immediately add to your configurations. For example, you can use <a href="https://github.com/errata-ai/Microsoft">Microsoft's style guide</a>.</p><p>Vale also provides ready-made style guides based on the purpose of your documentation. For example, if your documentation includes job listings, you can use the <a href="https://github.com/errata-ai/Joblint">Joblint</a> styles.</p><p>Vale is easy to <a href="https://vale.sh/docs/vale-cli/installation/">set up</a> and use. You can then either choose from <a href="https://github.com/errata-ai/packages">existing styles</a> or <a href="https://vale.sh/docs/topics/styles/">create your own</a>. Vale also provides a <a href="https://vale.sh/generator">config generator</a> to save you time.</p><p>Then, you can test your content by simply running a command like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">vale README.md</code></pre></div><p>Vale also has a <a href="https://github.com/errata-ai/vale-vscode">VS Code</a> extension that allows you to quickly catch errors and warnings in your editor.</p><p>Not only can you use Vale through the command line, but you can also integrate Vale into your development or release pipeline.</p><p>For example, Vale provides a <a href="https://github.com/errata-ai/vale-action">GitHub Action</a> that you can use to test whether a PR has any lint errors. You can then ensure that no errors are merged into your repositories by mistake.</p><h2 id="lint-code-with-eslint">Lint Code with ESLint</h2><p><a href="https://eslint.org/">ESLint</a> is a linter that allows you to identify problems in JavaScript code. It also allows you to enforce style rules in your code to ensure that everything is consistent.</p><p>There are plugins that allow running ESLint with other languages. For example, <a href="https://typescript-eslint.io/">typescript-eslint</a> allows linting TypeScript.</p><p>By default, ESLint wouldn't work for lining code in the documentation. The problem is that the linter has to recognize where code blocks are within the markdown file, recognize the language of the code block, then check if there are any errors in it.</p><p>To do that with ESLint, you'll need to use the <a href="https://github.com/eslint/eslint-plugin-markdown">eslint-plugin-markdown</a>. This plugin allows you to lint JavaScript, TypeScript, and other languages within your documentation files.</p><p>You can then define the rules similar to how you would with ESLint.</p><p>You can install the plugin in your Node.js project with the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> --save-dev eslint eslint-plugin-markdown</code></pre></div><p>Then, create the file <code class="language-text">.eslintrc.js</code> in the root directory with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token keyword">extends</span><span class="token operator">:</span> <span class="token string">"plugin:markdown/recommended"</span><span class="token punctuation">,</span> <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"markdown"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">overrides</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"**/*.md"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">processor</span><span class="token operator">:</span> <span class="token string">"markdown/markdown"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div><p>This enables running the linter on Markdown files. You can also add <code class="language-text">**/*.mdx</code> to the <code class="language-text">files</code> array to run the linter on MDX files as well.</p><p>You can specify which languages you want to lint in the <code class="language-text">overrides</code> array. For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token literal-property property">overrides</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token comment">//...</span> <span class="token punctuation">{</span> <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"**/*.md/*.js"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// optional</span> <span class="token literal-property property">rules</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span></code></pre></div><p>All languages are nested under <code class="language-text">**/*.md</code>. So, to specify JavaScript files, you pass the pattern <code class="language-text">**/*.md/*.js</code>.</p><p>You can also optionally pass rules specific to that language under the <code class="language-text">rules</code> property.</p><p>Then, you can run the <code class="language-text">eslint</code> command to test the code blocks in your documentation:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">eslint</code></pre></div><p>This assumes that you created the configuration file at the root of your project. Otherwise, you need to pass the <a href="https://eslint.org/docs/latest/user-guide/command-line-interface#-c---config">CLI tool some options</a>.</p><p>You can also pass it the <code class="language-text">--fix</code> option to immediately fix errors that can be fixed:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">eslint --fix</code></pre></div><p>You can also run ESLint when pull requests are sent into your repository by creating a GitHub Action that runs the above command. This ensures that all contributions to your project don't lead to errors in your documentation.</p><h2 id="conclusion">Conclusion</h2><p>This article lists two tools that can be used for configuring and automating linters both for the prose and the code of your documentation.</p><p>Although these tools are widely used, there are other tools that can be used for different types of documentation formats or projects. Regardless of what tool you use, invest in automating this process as it ensures clear documentation for developers.</p>]]></content:encoded></item><item><title><![CDATA[How to Get Elements From the DOM Using JavaScript]]></title><description><![CDATA[This tutorial shows you different ways to get an element from the DOM using JavaScript.]]></description><link>https://blog.shahednasser.com/how-to-get-elements-from-the-dom-using-javascript/</link><guid isPermaLink="false">Ghost__Post__631f8eea4e918d05f3537b51</guid><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 19 Sep 2022 10:58:26 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/e1e7a4c25e44c189d9cf97060890c67b/js-elm.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/e1e7a4c25e44c189d9cf97060890c67b/js-elm.jpg" alt="How to Get Elements From the DOM Using JavaScript"/><p>While creating a website and working with JavaScript, you'll often need to get access to elements in the DOM for different purposes.</p><p>This tutorial shows you different ways to get an element from the DOM using JavaScript.</p><h2 id="getelementbyid">getElementById</h2><p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById">getElementById()</a> method allows you to retrieve an element from the DOM using the element's ID.</p><p>If no element exists in the DOM with the supplied ID, <code class="language-text">null</code> will be returned instead.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> mainElement <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'main'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h2 id="getelementsbytagname">getElementsByTagName</h2><p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByTagName">getElementsByTagName()</a> allows you to retrieve an <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection">HTMLCollection</a> of elements that have the tag name you supply to the method. An example of a tag name is <code class="language-text">div</code>.</p><p>Items in an <code class="language-text">HTMLCollection</code> can be accessed similarly to how you would access items in an array.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> divElements <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementsByTagName</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>divElements<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>You can use this method on any element and not just the <code class="language-text">document</code>. That way, you can retrieve all children of that element that have the supplied tag name.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> divElements <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementsByTagName</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> pElements <span class="token operator">=</span> divElements<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">getElementsByTagName</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>pElements<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h2 id="getelementsbyclassname">getElementsByClassName()</h2><p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName">getElementsByClassName()</a> method allows you to retrieve a live <code class="language-text">HTMLCollection</code> of elements that have the class name you provide as a parameter.</p><p>A live <code class="language-text">HTMLCollection</code> means that the items in the collection are updated with any updates that happen to the DOM. So, for example, if an item was part of the collection because it had the class provided as a parameter, but then its class was removed, the item will be removed from the collection.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> mainElements <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementsByClassName</span><span class="token punctuation">(</span><span class="token string">'main'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>mainElements<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h2 id="getelementsbyname">getElementsByName()</h2><p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByName">getElementsByName()</a> method allows you to retrieve elements by the value of the <code class="language-text">name</code> attribute. For example, you can use it to retrieve <code class="language-text">input</code> elements that have the <code class="language-text">name</code> attribute set to <code class="language-text">email</code>.</p><p>This method returns a live <a href="https://developer.mozilla.org/en-US/docs/Web/API/NodeList">NodeList</a>, which is generally similar to an <code class="language-text">HTMLCollection</code>, but the items in the list can be accessed through the <a href="https://developer.mozilla.org/en-US/docs/Web/API/NodeList#methods">methods</a> it provides.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> emailElements <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementsByName</span><span class="token punctuation">(</span><span class="token string">'email'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>emailElements<span class="token punctuation">.</span><span class="token function">item</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h2 id="queryselector">querySelector</h2><p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector">querySelector()</a> method allows you to retrieve the first element that matches the specified selector. The selector can be any <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors">CSS selector</a>.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> elm <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.main > p'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>elm<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This method can be used on any element, and not just the <code class="language-text">document</code>. So, you can use it to retrieve a child element of a parent element that matches the specified selector.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> table <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.main > table'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> thead <span class="token operator">=</span> table<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'thead'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h2 id="queryselectorall">querySelectorAll</h2><p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll">querySelectorAll()</a> method allows you to retrieve all elements that match the specified selector. This method returns a <code class="language-text">NodeList</code>.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> elms <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">'.main > p'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>elms<span class="token punctuation">.</span><span class="token function">item</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This method can be used on any element, and not just the <code class="language-text">document</code>. So, you can use it to retrieve all child elements of a parent element that match the specified selector.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> table <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.main > table'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> rows <span class="token operator">=</span> table<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">'tr'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> row <span class="token keyword">of</span> rows<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>row<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><h2 id="children">children</h2><p>The <code class="language-text">children</code> property allows you to retrieve all immediate child elements of the <code class="language-text">document</code> or any element. This property's type is a live <code class="language-text">HTMLCollection</code>.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> rows <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">'table tr'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> row <span class="token keyword">of</span> rows<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>row<span class="token punctuation">.</span>children<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><h2 id="firstelementchild">firstElementChild</h2><p>The <code class="language-text">firstElementChild</code> property allows you to retrieve the first child element of the <code class="language-text">document</code> or any element.</p><p>If the element does not have children, the value of <code class="language-text">firstElementChild</code> is <code class="language-text">null</code>.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> rows <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">'table tr'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> row <span class="token keyword">of</span> rows<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>row<span class="token punctuation">.</span>firstElementChild<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><h2 id="lastelementchild">lastElementChild</h2><p>The <code class="language-text">lastElementChild</code> property allows you to retrieve the last child element of the <code class="language-text">document</code> or any element.</p><p>If the element does not have children, the value of <code class="language-text">lastElementChild</code> is <code class="language-text">null</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> rows <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">'table tr'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> row <span class="token keyword">of</span> rows<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>row<span class="token punctuation">.</span>lastElementChild<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><h2 id="scripts">scripts</h2><p>The <code class="language-text">scripts</code> property allows you to retrieve all <code class="language-text"><script></code> elements in the document. It returns an <code class="language-text">HTMLCollection</code> of elements.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>scripts<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h2 id="elementfrompoint">elementFromPoint</h2><p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/elementFromPoint">elementFromPoint()</a> method allows you to retrieve the top element starting from a specified point. It accepts x and y coordinates to locate the point to look for the element.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> elm <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">elemetFromPoint</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>elm<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h2 id="elementsfrompoint">elementsFromPoint</h2><p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/elementsFromPoint">elementsFromPoint()</a> method allows you to retrieve an array of Elements starting from a specified point until the end of the viewport.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> elms <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">elementsFromPoint</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>elm<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h2 id="closest">closest</h2><p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/closest">closest()</a> method available on elements (not on the <code class="language-text">document</code>) allows you to retrieve the closest ancestor (which are the parents) of the element that matches the specified selector. If no elements are found, the method returns <code class="language-text">null</code>.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> closestElm <span class="token operator">=</span> table<span class="token punctuation">.</span><span class="token function">closest</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>closestElm<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h2 id="nextelementsibling">nextElementSibling</h2><p>The <code class="language-text">nextElementSibling</code> property on elements (not on the <code class="language-text">document</code>) allows you to retrieve the element that follows the current element among its parent's child elements.</p><p>If there are no elements after this element, the value of the property will be <code class="language-text">null</code>.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>table<span class="token punctuation">.</span>nextElementSibling<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h2 id="previouselementsibling">previousElementSibling</h2><p>The <code class="language-text">previousElementSibling</code> property on elements (not on the <code class="language-text">document</code>) allows you to retrieve the element that proceeds the current element among its parent's child elements.</p><p>If there are no elements before this element, the value of the property will be <code class="language-text">null</code>.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>table<span class="token punctuation">.</span>previousElementSibling<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h2 id="conclusion">Conclusion</h2><p>This tutorial explores a list of methods and properties that you can use to retrieve elements in JavaScript. Each have different purposes and can be used differently based on your use case.</p>]]></content:encoded></item><item><title><![CDATA[Hacktoberfest 2022: Everything You Need to Know to Participate]]></title><description><![CDATA[This article explains what Hacktoberfest is, how you can participate, and more!]]></description><link>https://blog.shahednasser.com/hacktoberfest-2022-everything-you-need-to-know-to-participate/</link><guid isPermaLink="false">Ghost__Post__6320b1324e918d05f3537c2b</guid><category><![CDATA[Hacktoberfest]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 13 Sep 2022 17:11:43 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/e3af333cf15de537aedd86f455372ac9/hacktoberfest.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/e3af333cf15de537aedd86f455372ac9/hacktoberfest.jpg" alt="Hacktoberfest 2022: Everything You Need to Know to Participate"/><p>Hacktoberfest is an annual event that occurs in October. It is created by DigitalOcean. Thousands of developers participate in this event across the globe.</p><p>This article explains what Hacktoberfest is, how you can participate, and more!</p><h2 id="what-is-hacktoberfest">What is Hacktoberfest?</h2><p>As mentioned in the introduction, Hacktoberfest occurs every year during October. It encourages developers to contribute to open source projects and practice programming by participating in solving problems across projects.</p><h2 id="who-can-participate-in-hacktoberfest">Who Can Participate in Hacktoberfest?</h2><p>All developers of different levels and backgrounds can participate in Hacktoberfest. Whether you're a beginner or an expert, or a junior or a senior, you can participate in Hacktoberfest.</p><p>There are two ways to participate in Hacktoberfest: as a contributor or as a maintainer.</p><p>A contributor is someone that helps open source projects resolve issues they have opened. Whereas a maintainer manages an open source project and presents issues that they need help with.</p><h2 id="new-in-hacktoberfest-2022">New in Hacktoberfest 2022</h2><p>Hacktoberfest 2022 encourages low-code and non-code contributions, which can be done through blog posts, translating content, graphic design, and <a href="https://hacktoberfest.com/about/#low-or-non-code">more</a>. The contributions must be tracked through GitHub Pull Requests (PRs) as other types of contributions.</p><h2 id="how-to-participate-in-hacktoberfest-2022">How to Participate in Hacktoberfest 2022?</h2><h3 id="registration-to-hacktoberfest">Registration to Hacktoberfest</h3><p>Registration to Hacktoberfest opens on September 26th. When you register, you'll be able to choose whether you're participating as a contributor or as a maintainer.</p><h3 id="participating-as-a-contributor">Participating as a Contributor</h3><p>As a contributor, during October you must have four PRs that either:</p><ul><li>Are merged into a participating repository;</li><li>Or have the <code class="language-text">hacktoberfest-accepted</code> label;</li><li>Or have an approving review, but not closed or draft.</li></ul><p>A participating repository is a repository that has the <code class="language-text">hacktoberfest</code> topic. Participation can be done through GitHub or GitLab.</p><h3 id="participating-as-a-maintainer">Participating as a Maintainer</h3><p>To participate as a maintainer, you must facilitate participation for contributors. The first step is to either:</p><ol><li><a href="https://docs.github.com/en/enterprise-server@3.3/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/classifying-your-repository-with-topics#adding-topics-to-your-repository">Add the <code class="language-text">hacktoberfest</code> topic to your repository</a>;</li><li>Or add the <code class="language-text">hacktoberfest-accepted</code> label into your repository to be used on pull requests.</li></ol><p>Then, you must merge four PRs into your repository during October. If you decide to use the second option mentioned in the first step, make sure to add the <code class="language-text">hacktoberfest-accepted</code> label into these PRs.</p><h2 id="rules">Rules</h2><ol><li>For PRs to be counted into your participation in Hacktoberfest, they must be merged between October 1st and October 31st.</li><li>Contributions must be made to public repositories.</li><li>If a PR has a label that contains the word <code class="language-text">spam</code> in it, the PR will not be counted. Also, if a participant has 2 or more spam PRs, they'll be disqualified from Hacktoberfest.</li><li>If a PR has a label that contains the word <code class="language-text">invalid</code>, it will not be counted. The exception for this is if the PR also has the label <code class="language-text">hacktoberfest-accepted</code>.</li></ol><h2 id="unwritten-rules">Unwritten Rules</h2><p>This section covers rules that aren't necessarily covered by Hacktoberfest, but, from personal experience, are highly recommended to follow for both contributors and maintainers.</p><h3 id="for-contributors">For Contributors</h3><ol><li><strong>Do not spam any maintainer: </strong>Hacktoberfest is a busy season for maintainers, so they'll highly likely take time to take a look at your PR. Spamming maintainers does not speed up the process and only ruins the experience for maintainers.</li><li><strong>Make valuable contributions: </strong>During Hacktoberfest, many repositories are created with the purpose of participating in Hacktoberfest but without providing any value. For example, repositories where you just contribute by adding your name to a list. A lot of these repositories are caught by Hacktoberfest eventually, are disqualified, and contributions from them are labeled as invalid. There's no point in wasting time on this.</li><li><strong>Give back to your favorite projects: </strong>There are many projects out there that you have benefitted from throughout the year. Take this time to give back to these projects by helping them with the issues they have.</li><li><strong>Follow rules set by each project: </strong>Projects should have contributing guidelines that explain how you can contribute to them. Make sure you read those first before you contribute.</li></ol><h3 id="for-maintainers">For Maintainers</h3><ol><li><strong>Create contributing guidelines: </strong>Whether you have a small or big project, contributing guidelines make it easier for your contributors to know how they can contribute to your project.</li><li><strong>Welcome all developers: </strong>Many beginner developers participate in Hacktoberfest. They may lack experience when it comes to contributing, but they're eager to do it. Make sure to be welcoming to all developers of different experiences. If possible, try creating issues of different levels of expertise.</li></ol><h2 id="additional-resources">Additional Resources</h2><p>If you're interested in learning more about Hacktoberfest and how to contribute, here are some resources that can be helpful:</p><ol><li><a href="https://hacktoberfest.com/participation/">Hacktoberfest's participation page</a>.</li><li>For contributors: <a href="https://blog.shahednasser.com/tips-for-beginners-to-open-source">Tips for Beginners to Open Source Projects</a>.</li><li>For maintainers: <a href="https://blog.shahednasser.com/tips-for-beginner-maintainers-of-open-source-projects/">Tips for Beginner Maintainers of Open Source Projects</a>.</li><li><a href="https://github.com/mungell/awesome-for-beginners">Awesome for Beginners list</a>.</li></ol>]]></content:encoded></item><item><title><![CDATA[How to Become a Technical Writer?]]></title><description><![CDATA[This article explains briefly what technical writing is, and how you can become a technical writer.]]></description><link>https://blog.shahednasser.com/how-to-become-a-technical-writer/</link><guid isPermaLink="false">Ghost__Post__631d038c4e918d05f3537a81</guid><category><![CDATA[Technical Writing]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 12 Sep 2022 15:43:39 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/1473c5d430e02d6a66476028c06ab8e6/tech-writer.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/1473c5d430e02d6a66476028c06ab8e6/tech-writer.jpg" alt="How to Become a Technical Writer?"/><p>This year I <a href="https://blog.shahednasser.com/why-i-transitioned-from-a-full-stack-developer-to-a-technical-writer">transitioned</a><a href="https://blog.shahednasser.com/why-i-transitioned-from-a-full-stack-developer-to-a-technical-writer"> from a full-stack developer to a technical writer</a>. I started casually looking into technical writing and building my experience in it the year before until I realized that this was the path for me and decided to make the change.</p><p>This article explains briefly what technical writing is, and how you can become a technical writer.</p><h2 id="what-is-technical-writing">What is Technical Writing?</h2><p>Technical writing is the practice of writing down an explanation of how something technical works or can be used.</p><p>It can be in the format of a blog post or software documentation. For someone to become a technical writer, they also need technical knowledge.</p><h2 id="skills-you-need-to-become-a-technical-writer">Skills you Need to Become a Technical Writer</h2><p>This will come across as something obvious, but the main skills that you need to become a technical writer are two skills: technical skills and writing skills.</p><h3 id="technical-skills">Technical Skills</h3><p>It's important that before you become a technical writer, you take the time to build your experience as an engineer. </p><p>As your content will be used by other engineers or developers, you must be able to understand what kind of information they're looking for when they look at your content and in what format it should be presented.</p><p>Furthermore, you can't write explaining something that you don't have any actual knowledge of. For example, you can't explain how Promises work in JavaScript if you don't know what is JavaScript in the first place.</p><p>Even after you become a technical writer, it is important to keep on practicing development. Whether through reading about it and applying new knowledge or by maintaining side projects.</p><h3 id="writing-skills">Writing Skills</h3><p>Most technical content is written in English as it is a universal language that is understood by most people around the world. So, it's highly recommended that you improve your fluency in the English language.</p><p>It should be noted that being a good writer does not mean that you have to use "big words" in your writing. Good technical content should be written in a way that anyone with any level of language fluency would be able to understand.</p><h2 id="writing-technical-content-for-blogs">Writing Technical Content for Blogs</h2><p>If you're interested in becoming a technical writer who either writes on their own blog or writes for other blogs, this section is for you.</p><h3 id="own-blog">Own Blog</h3><p>Writing for your own blog can be highly beneficial for you, even if you don't want to become a technical writer. It showcases both your technical skills and your writing skills.</p><p>It also helps you find more freelance opportunities as a technical writer for other websites. It acts as a live resume.</p><p>Creating your own blog can seem like a big, difficult task, but that's actually not true.</p><p>One way to create your own blog is using platforms like <a href="https://hashnode.com/">Hashnode</a> or <a href="https://medium.com/">Medium</a>. It is for free and you don't need to manage your blog or the hosting, as that is done for you.</p><p>Alternatively, if you want more control over your blog and want to do things your own way, this can also be done with some solutions like <a href="https://ghost.org/">Ghost CMS</a>, <a href="https://strapi.io/">Strapi</a>, <a href="https://wordpress.com/">WordPress</a>, and more.</p><p>After you create your own blog, it becomes just a matter of "what will I write about?" The answer is anything and everything that you have knowledge of.</p><p>If you know a cool thing that you've discovered through personal experience, write about it. If you, instead, just learned about CSS Grids, write about it too.</p><p>The more you write, the more you'll be practicing while also sharing your knowledge with other developers. </p><h3 id="other-websites-and-blogs">Other Websites and Blogs</h3><p>Many websites pay technical writers to write content for them. This includes websites like <a href="https://www.sitepoint.com/write-for-us/">SitePoint</a>, <a href="https://draft.dev/">Draft.dev</a>, <a href="https://blog.logrocket.com/become-a-logrocket-guest-author/">LogRocket</a>, and more.</p><p>The application process for these websites is different, but generally speaking, you will need to apply through some kind of form where you fill out what technical and writing experiences you have.</p><p>If you have your own blog, you'll have a better chance of becoming a writer for these websites. Most websites rather see your experience beforehand to decide whether they want to work with you or not.</p><p>Writing for other websites increases your experience as a technical writer and helps you learn the different ways websites work with content. It can give you different insights and ideas for the content of your own as well.</p><h2 id="writing-documentation">Writing Documentation</h2><p>Another aspect of working as a technical writer is writing documentation. Documentation is a key asset for any developer using any software or tool. Good documentation provides a good developer experience.</p><p>Writing documentation requires thinking like a developer. "If I were using this tool, how would I want to learn about using it?" It's about finding the right way to deliver information of different complexities and experimenting with the best solution that you can provide for developers.</p><p>Documentation is similar to blog posts, except they usually delve more into the deeper topic and they are related to one piece of software.</p><p>You can learn about different good practices of writing documentation by observing well-written documentation such as <a href="https://stripe.com/docs">Stripe's documentation</a>.</p><p>I personally have learned a lot from reading <a href="https://docsfordevelopers.com/">Docs for Developers</a>, which is a book that explains the process of writing documentation from start to end in a very easy-to-understand language.</p><p>Unlike working with blogs, working with documentation generally means you have to be hired at a company and work on their documentation. If you have your own open-source solution, even if it's a small one, you can start by trying out writing documentation for it as a practice.</p><h2 id="conclusion">Conclusion</h2><p>Technical writing is a key asset to software development. It helps engineers learn how to use certain software and tools, and guide them to perform their own tasks while developing.</p><p>Whether you're interested in becoming a technical writer or not, I highly recommend writing in your free time and publishing it. It can boost your chance of getting opportunities both as a developer and as a writer, and it will help you understand topics you're writing about more deeply. </p>]]></content:encoded></item><item><title><![CDATA[What are Events in JavaScript and How to Handle Them?]]></title><description><![CDATA[This article helps beginners understand what Events are in JavaScript and how to handle them.]]></description><link>https://blog.shahednasser.com/what-are-events-in-javascript-and-how-to-handle-them/</link><guid isPermaLink="false">Ghost__Post__62f3f8304e918d05f3537963</guid><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 10 Aug 2022 19:49:03 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/c3e7617caba682aec0dbfe3b6d2bbd87/Events-in-JavaScript-3.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/c3e7617caba682aec0dbfe3b6d2bbd87/Events-in-JavaScript-3.jpg" alt="What are Events in JavaScript and How to Handle Them?"/><p>Events in JavaScript allow developers to listen for changes in the document and handle them as necessary. For example, you can listen to when a button is clicked to open a modal. Another example is showing the "scroll up" button when the user scrolls halfway through the page.</p><p>This article helps beginners understand what Events are in JavaScript and how to handle them.</p><h2 id="why-use-events">Why Use Events</h2><p>Modern websites have evolved to be interactive and reactive. Instead of presenting information or functionalities all at once, some can be shown to the user based on a specific action performed. The example mentioned earlier in the article illustrates this.</p><p>Events are also helpful in detecting different states of your website. For example, detecting when a screen is resized can help to ensure the responsiveness of certain elements on the page.</p><p>The list of use cases where events are helpful is endless. Events are an essential part of web development with JavaScript and it's important to understand how to use them.</p><h2 id="add-event-handler">Add Event Handler</h2><p>To listen to events, you can use the <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener">addEventListener</a> method. This method is available on every Element and Node in the document.</p><p><code class="language-text">addEventListener</code> accepts three parameters: the first parameter is the name of the event to listen to; the second parameter is the function that handles this event; and the third parameter is an optional parameter that allows you to set more <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#parameters">options for the listener</a>.</p><p>In most cases, you only need to use the first two parameters. Here's an example of handling the <code class="language-text">click</code> event on a button:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> button<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Button clicked"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This retrieves the first button on the page and, when the button is clicked, shows an alert.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/08/Screen-Shot-2022-08-10-at-9.39.02-PM.png" class="kg-image" alt="What are Events in JavaScript and How to Handle Them?" loading="lazy" width="880" height="252" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/08/Screen-Shot-2022-08-10-at-9.39.02-PM.png 600w, https://backend.shahednasser.com/content/images/2022/08/Screen-Shot-2022-08-10-at-9.39.02-PM.png 880w" sizes="(min-width: 720px) 720px"/></figure><h3 id="can-an-event-have-more-than-one-handler">Can an Event Have More Than One Handler?</h3><p>The same event can have many handlers. The handlers are triggered one by one when the event occurs.</p><h3 id="event-object">Event Object</h3><p>As you can see, the function passed as a second parameter to <code class="language-text">addEventListener</code> received the argument <code class="language-text">e</code>. This is an <a href="https://developer.mozilla.org/en-US/docs/Web/API/Event">Event</a> object. This object may have different properties depending on its underlying type. However, it has some common important properties.</p><p>A frequently used property on the Event object is the <code class="language-text">target</code> property. This is the element that the event was triggered on. This can be helpful when you have the same handler for more than one element.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"input"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"change"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This code snippet adds an event handler to the first <code class="language-text">input</code> element on the <code class="language-text">change</code> event. The <code class="language-text">change</code> event is triggered when you change the value of the input, then move the focus from the input (for example, click on something else on the page).</p><p>When the <code class="language-text">change</code> event occurs and the handler is triggered, the value of the input is retrieved using <code class="language-text">e.target.value</code> and used in an alert.</p><h3 id="prevent-default-behavior-of-the-event">Prevent Default Behavior of the Event</h3><p>In some cases, you want to prevent the default behavior of certain events. For example, when a link is clicked on a page, you might want to show a confirmation message before the user is actually taken to a new page.</p><p>To prevent the default behavior of an event, you can use the <code class="language-text">preventDefault()</code> method on the Event object.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> a <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"a.some-link"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> a<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token function">confirm</span><span class="token punctuation">(</span><span class="token string">"Are you sure?"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> window<span class="token punctuation">.</span>location<span class="token punctuation">.</span>href <span class="token operator">=</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>href<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This adds an event handler to the <code class="language-text">click</code> events on a link that has the class <code class="language-text">some-link</code>. In the event handler, <code class="language-text">e.preventDefault()</code> is used to prevent the default behavior of opening the page indicated in the <code class="language-text">href</code> attribute.</p><p>It then shows the user a confirmation window, and if the user clicks Yes on the confirmation window, it then opens the page as expected.</p><h3 id="prevent-other-handlers-from-handling-this-event">Prevent Other Handlers from Handling this Event</h3><p>As mentioned earlier, an event can have more than one handler. However, in some cases, you might want to cancel other events from handling this event. For example, if a request is sent to the server on form submission and you don't want other event handlers of form submission to send more requests.</p><p>There are two methods that can be used to prevent other handlers from handling the same event: <code class="language-text">stopPropagation</code> and <code class="language-text">stopImmediatePropagation</code>.</p><p><code class="language-text">stopPropagation</code> is used to prevent other event handlers from handling an event during the bubbling phase. </p><p>Bubbling is when you have the same event on both child and parent elements. The event will be triggered first on the child element, then "bubbled" to the parent element.</p><p>In this case, <code class="language-text">stopPropagation</code> prevents the event from being triggered on the parent element if called in the handler of the child element. However, it does not prevent the event from propagating to other event handlers.</p><p>To prevent the event from being handled by subsequent handlers, you can use <code class="language-text">stopImmediatePropagation</code>.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> button<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">stopImmediatePropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Hello!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> button<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Bye!"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Although the button has two event handlers that listen to the <code class="language-text">click</code> event, only the first one will run since it calls the <code class="language-text">stopImmediatePropagation</code> function.</p><h3 id="difference-between-preventdefault-stoppropagation-and-stopimmediatepropagation">Difference Between preventDefault, stopPropagation, and stopImmediatePropagation</h3><p><code class="language-text">preventDefault</code> only prevents the default behavior of the event. However, it does not prevent other handlers from handling the event.</p><p><code class="language-text">stopPropagation</code> and <code class="language-text">stopImmediatePropagation</code> only prevent other handlers from handling the event. However, they don't prevent the default behavior of the event.</p><p>If you want to prevent both the default behavior and other handlers from handling the event, use <code class="language-text">preventDefault</code> with either <code class="language-text">stopPropagation</code> or <code class="language-text">stopImmediatePropagation</code>.</p><h3 id="handle-events-on-dynamic-elements">Handle Events on Dynamic Elements</h3><p>Consider the following example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> buttons <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">".btn"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> buttons<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">btn</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> btn<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Hello!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">//create new button</span> <span class="token keyword">const</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> button<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">'btn'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> button<span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token string">"Bye"</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>button<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>In this example, you first retrieve all buttons that have the class <code class="language-text">btn</code>. Then, you loop over these buttons and add an event listener that just shows the alert "Hello" when the button is clicked.</p><p>Then, you dynamically create a new button, add the class <code class="language-text">btn</code> to that button, and add it to the <code class="language-text">body</code> of the document.</p><p>If you try clicking buttons that were added in the HTML of the document or that were added prior to adding the event listener, the alert will be shown as expected. However, if you click on the new button, no alert will be shown. </p><p>This is because the element was not part of the elements retrieved using <code class="language-text">querySelectorAll</code> as it didn't exist at the time.</p><p>Although this is a reasonable outcome, in larger websites, you might not be able to attach an event handler every time you create a new element, or you might want to ensure that the event handler is added to all elements, whether originally or dynamically created, similarly.</p><p>In that case, instead of adding the event handler directly to each element separately, you can add the event handler to the document's <code class="language-text">body</code> and use <code class="language-text">e.target</code> to check if the element triggered matches a specific condition.</p><p>For example, you can transform the previous example to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span><span class="token string">"btn"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Hello!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">//create new button</span> <span class="token keyword">const</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> button<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">'btn'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> button<span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token string">"Bye"</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>button<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>You add a handler to the <code class="language-text">click</code> event on the <code class="language-text">body</code>. In the handler, you check if <code class="language-text">e.target</code> has the class <code class="language-text">btn</code> and only perform the necessary action if it does.</p><p>Now, when any of the elements that have the class <code class="language-text">btn</code>, whether dynamically or initially created, are clicked, the event handler will run for them.</p><p>This approach, however, will run the event listener on every click event on the body. So, it's important to handle it based on the target carefully.</p><h2 id="remove-event-handler">Remove Event Handler</h2><p>In some cases, you might want to remove an event handler for an element. To do that, you can use the <code class="language-text">removeEventListener</code> method. This method is available on every Element and Node in the document.</p><p>This method receives the same parameters <code class="language-text">addEventListener</code> receives. It's important to pass the same function that you passed to <code class="language-text">addEventListener</code>. For that reason, people commonly define the function separately, then pass it to <code class="language-text">addEventListener</code> and <code class="language-text">removeEventListener</code>.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handleClick</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Hello"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> button<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> handleClick<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//some time later</span> button<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> handleClick<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h2 id="conclusion">Conclusion</h2><p>This article scratches the surface of Events and helps you understand them better. To learn more about Events in JavaScript, check out the following resources:</p><ol><li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to Events</a></li><li><a href="https://developer.mozilla.org/en-US/docs/Web/Events">Event Reference</a></li></ol>]]></content:encoded></item><item><title><![CDATA[React (TanStack) Query Tutorial for Beginners]]></title><description><![CDATA[In this tutorial, you'll build a simple Node.js server and then learn how to interact with it on a React website using React Query.]]></description><link>https://blog.shahednasser.com/react-query-tutorial-for-beginners/</link><guid isPermaLink="false">Ghost__Post__62dd14674e918d05f353777d</guid><category><![CDATA[React]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sun, 24 Jul 2022 15:50:35 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/49810f1cc6a34556c1ce36e3061364ce/React--TanStack--Query-Tutorial-for-Beginners.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/49810f1cc6a34556c1ce36e3061364ce/React--TanStack--Query-Tutorial-for-Beginners.jpg" alt="React (TanStack) Query Tutorial for Beginners"/><p>React Query (now rebranded to TanStack Query) is a React library used to make fetching and manipulating server-side data easier. Using React Query, you can implement, along with data fetching, caching, and synchronization of your data with the server.</p><p>In this tutorial, you'll build a simple Node.js server and then learn how to interact with it on a React website using React Query.</p><p>Please note that this version uses v4 of React Query which is now named TanStack Query.</p><p>You can find the code for this tutorial in <a href="https://github.com/shahednasser/react-query-tutorial">this GitHub repository</a>.</p><h2 id="prerequisites">Prerequisites</h2><p> Before starting with this tutorial make sure you have <a href="https://nodejs.org/en/">Node.js installed</a>. You need at least version 14.</p><h2 id="server-setup">Server Setup</h2><p>In this section, you'll set up a simple Node.js server with an SQLite database. The server has 3 endpoints to fetch, add, and delete notes.</p><p>If you already have a server you can skip this section and go to the Website Setup section.</p><h3 id="create-server-project">Create Server Project</h3><p>Create a new directory called <code class="language-text">server</code> then initialize a new project using NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> server <span class="token builtin class-name">cd</span> server <span class="token function">npm</span> init -y</code></pre></div><h3 id="install-dependencies">Install Dependencies</h3><p>Then, install the packages you'll need for the development of the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i express cors body-parser sqlite3 nodemon</code></pre></div><p>Here's what each of the packages is for:</p><ol><li><code class="language-text">express</code> to create a server using <a href="https://expressjs.com/">Express</a>.</li><li><code class="language-text">cors</code> is an Express middleware used to handle <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">CORS</a> on your server.</li><li><code class="language-text">body-parser</code> is an Express middleware used to parse the body of a request.</li><li><code class="language-text">sqlite3</code> is an SQLite database adapter for Node.js.</li><li><code class="language-text">nodemon</code> is a library used to restart the server whenever new changes occur to the files.</li></ol><h3 id="create-server">Create Server</h3><p>Create the file <code class="language-text">index.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'express'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> port <span class="token operator">=</span> <span class="token number">3001</span><span class="token punctuation">;</span> <span class="token keyword">const</span> cors <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'cors'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> sqlite3 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'sqlite3'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">verbose</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> bodyParser <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'body-parser'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>bodyParser<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token function">cors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span>port<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Notes app listening on port </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>port<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This initializes the server using Express on port <code class="language-text">3001</code>. It also uses the <code class="language-text">cors</code> and <code class="language-text">body-parser</code> middleware.</p><p>Then, in <code class="language-text">package.json</code> add a new script <code class="language-text">start</code> to run the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"> <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"start"</span><span class="token operator">:</span> <span class="token string">"nodemon index.js"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><h3 id="initialize-the-database">Initialize the Database</h3><p>In <code class="language-text">index.js</code> before <code class="language-text">app.listen</code> add the following code:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> db <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">sqlite3<span class="token punctuation">.</span>Database</span><span class="token punctuation">(</span><span class="token string">'data.db'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> err<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// create tables if they don't exist</span> db<span class="token punctuation">.</span><span class="token function">serialize</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> db<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, content TEXT, created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This creates a new database if it doesn't exist in the file <code class="language-text">data.db</code>. Then, if the <code class="language-text">notes</code> table doesn't exist on the database it creates it as well.</p><h3 id="add-endpoints">Add Endpoints</h3><p>Following the database code, add the following code to add the endpoints:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/notes'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> db<span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token string">'SELECT * FROM notes'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err<span class="token punctuation">,</span> rows</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'An error occurred, please try again later'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">data</span><span class="token operator">:</span> rows <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/notes/:id'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> db<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'SELECT * FROM notes WHERE id = ?'</span><span class="token punctuation">,</span> req<span class="token punctuation">.</span>params<span class="token punctuation">.</span>id<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err<span class="token punctuation">,</span> row</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'An error occurred, please try again later'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>row<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'Note does not exist'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">data</span><span class="token operator">:</span> row <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">'/notes'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> title<span class="token punctuation">,</span> content <span class="token punctuation">}</span> <span class="token operator">=</span> req<span class="token punctuation">.</span>body<span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>title <span class="token operator">||</span> <span class="token operator">!</span>content<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">400</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'title and content are required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> db<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token string">'INSERT INTO notes (title, content) VALUES (?, ?)'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>title<span class="token punctuation">,</span> content<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'An error occurred, please try again later'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>lastID<span class="token punctuation">,</span> title<span class="token punctuation">,</span> content<span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token string">'/notes/:id'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> id <span class="token punctuation">}</span> <span class="token operator">=</span> req<span class="token punctuation">.</span>params<span class="token punctuation">;</span> db<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'SELECT * FROM notes WHERE id = ?'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>id<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err<span class="token punctuation">,</span> row</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'An error occurred, please try again later'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>row<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'Note does not exist'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> db<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token string">'DELETE FROM notes WHERE id = ?'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>id<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'An error occurred, please try again later'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'Note deleted successfully'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Briefly, this creates 4 endpoints:</p><ol><li><code class="language-text">/notes</code> endpoint of the method <code class="language-text">GET</code> to fetch all notes.</li><li><code class="language-text">/notes/:id</code> endpoint of the method <code class="language-text">GET</code> to fetch a note by an ID.</li><li><code class="language-text">/notes</code> endpoint of the method <code class="language-text">POST</code> to add a note.</li><li><code class="language-text">/notes/:id</code> endpoint of the method <code class="language-text">DELETE</code> to delete a note.</li></ol><h3 id="test-server">Test Server</h3><p>Run the following command to start the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>This starts the server on port <code class="language-text">3001</code>. You can test it out by sending a request to <code class="language-text">localhost:3001/notes</code>.</p><h2 id="website-setup">Website Setup</h2><p>In this section, you'll create the website with Create React App (CRA). This is where you'll make use of React Query.</p><h3 id="create-website-project">Create Website Project</h3><p>To create a new React app, run the following command in a different directory:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-react-app website</code></pre></div><p>This creates a new React app in the directory <code class="language-text">website</code>.</p><h3 id="install-dependencies-1">Install Dependencies</h3><p>Run the following command to change to the <code class="language-text">website</code> directory and install the necessary dependencies for the website:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> website <span class="token function">npm</span> i @tanstack/react-query tailwindcss postcss autoprefixer @tailwindcss/typography @heroicons/react @windmill/react-ui</code></pre></div><p>The <code class="language-text">@tanstack/react-query</code> library is the React Query library which is now named TanStack Query. The other libraries are <a href="https://tailwindcss.com/">Tailwind CSS</a> related libraries to add styling to the website.</p><h3 id="tailwind-css-setup">Tailwind CSS Setup</h3><p>This section is optional and is only used to set up Tailwind CSS.</p><p>Create the file <code class="language-text">postcss.config.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">tailwindcss</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">autoprefixer</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> </code></pre></div><p>Also, create the file <code class="language-text">tailwind.config.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token comment">/** @type {import('tailwindcss').Config} */</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"./src/**/*.{js,jsx,ts,tsx}"</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">theme</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">extend</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'@tailwindcss/typography'</span><span class="token punctuation">)</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> </code></pre></div><p>Then, create the file <code class="language-text">src/index.css</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@tailwind</span> base<span class="token punctuation">;</span></span> <span class="token atrule"><span class="token rule">@tailwind</span> components<span class="token punctuation">;</span></span> <span class="token atrule"><span class="token rule">@tailwind</span> utilities<span class="token punctuation">;</span></span></code></pre></div><p>Finally, in <code class="language-text">index.js</code> import <code class="language-text">src/index.css</code> at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token string">'./index.css'</span><span class="token punctuation">;</span></code></pre></div><h3 id="use-queryclientprovider">Use QueryClientProvider</h3><p>To use the React Query client in all of your components, you must use it at a high level in your website's components hierarchy. The best place to put it is in <code class="language-text">src/index.js</code> which wraps up your entire website's components.</p><p>In <code class="language-text">src/index.js</code> add the following imports at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> QueryClient<span class="token punctuation">,</span> QueryClientProvider<span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@tanstack/react-query'</span></code></pre></div><p>Then, initialize a new Query client:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> queryClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">QueryClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre></div><p>Finally, change the parameter passed to <code class="language-text">root.render</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">root<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span> <span class="token operator"><</span>QueryClientProvider client<span class="token operator">=</span><span class="token punctuation">{</span>queryClient<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>App <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>QueryClientProvider<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This wraps the <code class="language-text">App</code> component which holds the rest of the website's components with <code class="language-text">QueryClientProvider</code>. This provider accepts the prop <code class="language-text">client</code> which is an instance of <code class="language-text">QueryClient</code>.</p><p>Now, all components within the website will have access to the Query Client which is used to fetch, cache, and manipulate the server data.</p><h3 id="implement-display-notes">Implement Display Notes</h3><p>Fetching data from the server is an act of performing a query. Therefore, you'll use <code class="language-text">useQuery</code> in this section.</p><p>You'll display notes in the <code class="language-text">App</code> component. These notes are fetched from the server using the <code class="language-text">/notes</code> endpoint.</p><p>Replace the content of <code class="language-text">app.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> PlusIcon<span class="token punctuation">,</span> RefreshIcon <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@heroicons/react/solid'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useMutation<span class="token punctuation">,</span> useQuery<span class="token punctuation">,</span> useQueryClient <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@tanstack/react-query'</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> isLoading<span class="token punctuation">,</span> isError<span class="token punctuation">,</span> data<span class="token punctuation">,</span> error <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useQuery</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'notes'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> fetchNotes<span class="token punctuation">)</span> <span class="token keyword">function</span> <span class="token function">fetchNotes</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'http://localhost:3001/notes'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> success<span class="token punctuation">,</span> data <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>success<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span> <span class="token punctuation">(</span><span class="token string">'An error occurred while fetching notes'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> data<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"w-screen h-screen overflow-x-hidden bg-red-400 flex flex-col justify-center items-center"</span><span class="token operator">></span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">'bg-white w-full md:w-1/2 p-5 text-center rounded shadow-md text-gray-800 prose'</span><span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span>Notes<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token punctuation">{</span>isLoading <span class="token operator">&&</span> <span class="token operator"><</span>RefreshIcon className<span class="token operator">=</span><span class="token string">"w-10 h-10 animate-spin mx-auto"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>RefreshIcon<span class="token operator">></span><span class="token punctuation">}</span> <span class="token punctuation">{</span>isError <span class="token operator">&&</span> <span class="token operator"><</span>span className<span class="token operator">=</span><span class="token string">'text-red'</span><span class="token operator">></span><span class="token punctuation">{</span>error<span class="token punctuation">.</span>message <span class="token operator">?</span> error<span class="token punctuation">.</span>message <span class="token operator">:</span> error<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><span class="token punctuation">}</span> <span class="token punctuation">{</span><span class="token operator">!</span>isLoading <span class="token operator">&&</span> <span class="token operator">!</span>isError <span class="token operator">&&</span> data <span class="token operator">&&</span> <span class="token operator">!</span>data<span class="token punctuation">.</span>length <span class="token operator">&&</span> <span class="token operator"><</span>span className<span class="token operator">=</span><span class="token string">'text-red-400'</span><span class="token operator">></span>You have no notes<span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><span class="token punctuation">}</span> <span class="token punctuation">{</span>data <span class="token operator">&&</span> data<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">&&</span> data<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">note<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>div key<span class="token operator">=</span><span class="token punctuation">{</span>note<span class="token punctuation">.</span>id<span class="token punctuation">}</span> className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">text-left </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>index <span class="token operator">!==</span> data<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span> <span class="token operator">?</span> <span class="token string">'border-b pb-2'</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>h2<span class="token operator">></span><span class="token punctuation">{</span>note<span class="token punctuation">.</span>title<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span> <span class="token operator"><</span>p<span class="token operator">></span><span class="token punctuation">{</span>note<span class="token punctuation">.</span>content<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator"><</span>span<span class="token operator">></span> <span class="token operator"><</span>button className<span class="token operator">=</span><span class="token string">'link text-gray-400'</span><span class="token operator">></span>Delete<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>button className<span class="token operator">=</span><span class="token string">"mt-2 bg-gray-700 hover:bg-gray-600 rounded-full text-white p-3"</span><span class="token operator">></span> <span class="token operator"><</span>PlusIcon className<span class="token operator">=</span><span class="token string">'w-5 h-5'</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>PlusIcon<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span></code></pre></div><p>Here's briefly what's going on in this code snippet:</p><ol><li>You use <code class="language-text">useQuery</code> to fetch the notes. The first parameter it accepts is a unique key used for caching. The second parameter is the function used to fetch the data. You pass it the <code class="language-text">fetchNotes</code> function.</li><li><code class="language-text">useQuery</code> returns an object that holds <a href="https://tanstack.com/query/v4/docs/reference/useQuery">many variables</a>. Here, you use 4 of them: <code class="language-text">isLoading</code> is a boolean value that determines whether the data is currently being fetched; <code class="language-text">isError</code> is a boolean value that determines if an error occurred. <code class="language-text">data</code> is the data that is fetched from the server; and <code class="language-text">error</code> is the error message if <code class="language-text">isError</code> is true.</li><li>The <code class="language-text">fetchNotes</code> function must return a promise that either resolves data or throws an error. In the function, you send a <code class="language-text">GET</code> request to <code class="language-text">localhost:3001/notes</code> to fetch the notes. If the data is fetched successfully it is returned in the <code class="language-text">then</code> fulfillment function. </li><li>In the returned JSX, if <code class="language-text">isLoading</code> is true, a loading icon is shown. If <code class="language-text">isError</code> is true, an error message is shown. If <code class="language-text">data</code> is fetched successfully and has any data in it, the notes are rendered.</li><li>You also show a button with a plus icon to add new notes. You'll implement this later.</li></ol><h3 id="test-displaying-notes">Test Displaying Notes</h3><p>To test out what you've implemented so far, make sure your server is still running, then start your React app server with the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>This runs your React app on <code class="language-text">localhost:3000</code> by default. If you open it in your browser, you'll see a loading icon at first then you'll see no notes as you haven't added any yet.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/07/Screen-Shot-2022-06-28-at-9.10.04-PM.png" class="kg-image" alt="React (TanStack) Query Tutorial for Beginners" loading="lazy" width="1446" height="490" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/07/Screen-Shot-2022-06-28-at-9.10.04-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/07/Screen-Shot-2022-06-28-at-9.10.04-PM.png 1000w, https://backend.shahednasser.com/content/images/2022/07/Screen-Shot-2022-06-28-at-9.10.04-PM.png 1446w" sizes="(min-width: 720px) 720px"/></figure><h3 id="implement-add-notes-functionality">Implement Add Notes Functionality</h3><p>Adding a note is an act of mutation on the server data. Therefore, you'll be using the <code class="language-text">useMutation</code> hook in this section.</p><p>You'll create a separate component that shows the form used to add a note.</p><p>Create the file <code class="language-text">src/form.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useMutation<span class="token punctuation">,</span> useQueryClient <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@tanstack/react-query'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Form</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> isOpen<span class="token punctuation">,</span> setIsOpen <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>title<span class="token punctuation">,</span> setTitle<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>content<span class="token punctuation">,</span> setContent<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span> <span class="token keyword">const</span> queryClient <span class="token operator">=</span> <span class="token function">useQueryClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> mutation <span class="token operator">=</span> <span class="token function">useMutation</span><span class="token punctuation">(</span>insertNote<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token function-variable function">onSuccess</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setTitle</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span> <span class="token function">setContent</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">function</span> <span class="token function">closeForm</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token function">setIsOpen</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">insertNote</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">http://localhost:3001/notes</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">'POST'</span><span class="token punctuation">,</span> <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'Content-Type'</span><span class="token operator">:</span> <span class="token string">'application/json'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span> title<span class="token punctuation">,</span> content <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> success<span class="token punctuation">,</span> data <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>success<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"An error occured"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">setIsOpen</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span> queryClient<span class="token punctuation">.</span><span class="token function">setQueriesData</span><span class="token punctuation">(</span><span class="token string">'notes'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">old</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token operator">...</span>old<span class="token punctuation">,</span> data<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span> mutation<span class="token punctuation">.</span><span class="token function">mutate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">absolute w-full h-full top-0 left-0 z-50 flex justify-center items-center </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token operator">!</span>isOpen <span class="token operator">?</span> <span class="token string">'hidden'</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">'bg-black opacity-50 absolute w-full h-full top-0 left-0'</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>form className<span class="token operator">=</span><span class="token string">'bg-white w-full md:w-1/2 p-5 rounded shadow-md text-gray-800 prose relative'</span> onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>h2 className<span class="token operator">=</span><span class="token string">'text-center'</span><span class="token operator">></span>Add Note<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span> <span class="token punctuation">{</span>mutation<span class="token punctuation">.</span>isError <span class="token operator">&&</span> <span class="token operator"><</span>span className<span class="token operator">=</span><span class="token string">'block mb-2 text-red-400'</span><span class="token operator">></span><span class="token punctuation">{</span>mutation<span class="token punctuation">.</span>error<span class="token punctuation">.</span>message <span class="token operator">?</span> mutation<span class="token punctuation">.</span>error<span class="token punctuation">.</span>message <span class="token operator">:</span> mutation<span class="token punctuation">.</span>error<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"text"</span> placeholder<span class="token operator">=</span><span class="token string">'Title'</span> className<span class="token operator">=</span><span class="token string">'rounded-sm w-full border px-2'</span> value<span class="token operator">=</span><span class="token punctuation">{</span>title<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setTitle</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>textarea onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setContent</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> className<span class="token operator">=</span><span class="token string">"rounded-sm w-full border px-2 mt-2"</span> placeholder<span class="token operator">=</span><span class="token string">'Content'</span> value<span class="token operator">=</span><span class="token punctuation">{</span>content<span class="token punctuation">}</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>textarea<span class="token operator">></span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string">"submit"</span> className<span class="token operator">=</span><span class="token string">'mt-2 bg-red-400 hover:bg-red-600 text-white p-3 rounded mr-2 disabled:pointer-events-none'</span> disabled<span class="token operator">=</span><span class="token punctuation">{</span>mutation<span class="token punctuation">.</span>isLoading<span class="token punctuation">}</span><span class="token operator">></span> Add<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span>button className<span class="token operator">=</span><span class="token string">'mt-2 bg-gray-700 hover:bg-gray-600 text-white p-3 rounded'</span> onClick<span class="token operator">=</span><span class="token punctuation">{</span>closeForm<span class="token punctuation">}</span><span class="token operator">></span>Cancel<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>Here's a brief explanation of this form</p><ol><li>This form acts as a pop-up. It accepts <code class="language-text">isOpen</code> and <code class="language-text">setIsOpen</code> props to determine when the form is opened and handle closing it.</li><li>You use <code class="language-text">useQueryClient</code> to get access to the Query Client. This is necessary to perform a mutation.</li><li>To handle adding a note on your server and keep all data in your query client synced, you must the <code class="language-text">useMutation</code> hook. </li><li>The <code class="language-text">useMutation</code> hook accepts 2 parameters. Thie first one is the function that will handle the mutation, which in this case is <code class="language-text">insertNote</code>. The second parameter is an object of <a href="https://tanstack.com/query/v4/docs/reference/useMutation">options</a>. You pass it one option <code class="language-text">onSuccess</code> which is a function that runs if the mutation is performed successfully. You use this to reset the <code class="language-text">title</code> and <code class="language-text">content</code> fields of the form.</li><li>In <code class="language-text">insertNote</code>, you send a <code class="language-text">POST</code> request to <code class="language-text">localhost:3001/notes</code> and pass in the body the <code class="language-text">title</code> and <code class="language-text">content</code> of the note to be created. If the <code class="language-text">success</code> body parameter returned from the server is <code class="language-text">false</code>, an error is thrown to signal that the mutation failed. </li><li>If the note is added successfully, you change the cached value of the <code class="language-text">notes</code> key using the <code class="language-text">queryClient.setQueriesData</code> method. This method accepts the key as a first parameter and the new data associated with that key as a second parameter. This updates the data everywhere it's used on your website.</li><li>In this component you display a form with 2 fields: <code class="language-text">title</code> and <code class="language-text">content</code>. In the form, you check if an error occurs using <code class="language-text">mutation.isError</code> and get access to the error using <code class="language-text">mutation.error</code>.</li><li>You handle form submission in the <code class="language-text">handleSubmit</code> function. Here, you trigger the mutation using <code class="language-text">mutation.mutate</code>. This is where the <code class="language-text">insertNote</code> function is triggered to add a new note.</li></ol><p>Then, in <code class="language-text">src/app.js</code> add the following imports at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Form <span class="token keyword">from</span> <span class="token string">'./form'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span></code></pre></div><p>Then, at the beginning of the component add a new state variable to manage wheter the form is opened or not:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>isOpen<span class="token punctuation">,</span> setIsOpen<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span></code></pre></div><p>Next, add a new function <code class="language-text">addNote</code> that just uses <code class="language-text">setIsOpen</code> to open the form:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">addNote</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setIsOpen</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>Finally, in the returned JSX, replace the button with the plus icon with the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>button className<span class="token operator">=</span><span class="token string">"mt-2 bg-gray-700 hover:bg-gray-600 rounded-full text-white p-3"</span> onClick<span class="token operator">=</span><span class="token punctuation">{</span>addNote<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>PlusIcon className<span class="token operator">=</span><span class="token string">'w-5 h-5'</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>PlusIcon<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span>Form isOpen<span class="token operator">=</span><span class="token punctuation">{</span>isOpen<span class="token punctuation">}</span> setIsOpen<span class="token operator">=</span><span class="token punctuation">{</span>setIsOpen<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>This sets the <code class="language-text">onClick</code> handler of the button to <code class="language-text">addNote</code>. It also adds the <code class="language-text">Form</code> component you created earlier as a child component of <code class="language-text">App</code>. </p><h3 id="test-adding-a-note">Test Adding a Note</h3><p>Rerun your server and React app if they're not running. Then, open the website again at <code class="language-text">localhost:3000</code>. Click on the plus button and a pop up will open with the form to add a new note.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/07/Screen-Shot-2022-07-24-at-6.31.41-PM.png" class="kg-image" alt="React (TanStack) Query Tutorial for Beginners" loading="lazy" width="1494" height="792" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/07/Screen-Shot-2022-07-24-at-6.31.41-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/07/Screen-Shot-2022-07-24-at-6.31.41-PM.png 1000w, https://backend.shahednasser.com/content/images/2022/07/Screen-Shot-2022-07-24-at-6.31.41-PM.png 1494w" sizes="(min-width: 720px) 720px"/></figure><p>Enter a random title and content then click Add. The pop up form will then close and you can see the new note added.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/07/Screen-Shot-2022-07-24-at-6.32.53-PM.png" class="kg-image" alt="React (TanStack) Query Tutorial for Beginners" loading="lazy" width="1418" height="720" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/07/Screen-Shot-2022-07-24-at-6.32.53-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/07/Screen-Shot-2022-07-24-at-6.32.53-PM.png 1000w, https://backend.shahednasser.com/content/images/2022/07/Screen-Shot-2022-07-24-at-6.32.53-PM.png 1418w" sizes="(min-width: 720px) 720px"/></figure><h3 id="implement-delete-note-functionality">Implement Delete Note Functionality</h3><p>The last functionality you'll add is deleting notes. Deleting a note is another act of mutation as it manipulates the server's data.</p><p>At the beginning of the <code class="language-text">App</code> component in <code class="language-text">src/app.js</code> add the following code:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> queryClient <span class="token operator">=</span> <span class="token function">useQueryClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> mutation <span class="token operator">=</span> <span class="token function">useMutation</span><span class="token punctuation">(</span>deleteNote<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token function-variable function">onSuccess</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> queryClient<span class="token punctuation">.</span><span class="token function">invalidateQueries</span><span class="token punctuation">(</span><span class="token string">'notes'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Here, you get access to the query client using <code class="language-text">useQueryClient</code>. Then, you create a new mutation using <code class="language-text">useMutation</code>. You pass it the function <code class="language-text">deleteNote</code> (which you'll create next) as a first parameter and an object of options. </p><p>To the <code class="language-text">onSuccess</code> option you pass a function that does one thing. It executes the method <code class="language-text">queryClient.invalidateQueries</code>. This method marks the cached data for a specific key as outdated, which triggers retrieving the data again. </p><p>So, once a note is deleted, the query you created earlier that executes the function <code class="language-text">fetchNotes</code> will be triggered and the notes will be fetched again. If you had created other queries on your website that use the same key <code class="language-text">notes</code>, they'll also be triggered to update their data. </p><p>Next, add the function <code class="language-text">deleteNote</code> in the <code class="language-text">App</code> component in the same file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">deleteNote</span> <span class="token punctuation">(</span><span class="token parameter">note</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">http://localhost:3001/notes/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>note<span class="token punctuation">.</span>id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">'DELETE'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> success<span class="token punctuation">,</span> message <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>success<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">alert</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>This function receives the <code class="language-text">note</code> to be deleted as a parameter. It sends a <code class="language-text">DELETE</code> request to <code class="language-text">localhost:3001/notes/:id</code>. If the <code class="language-text">success</code> body parameter of the response is <code class="language-text">false</code>, an error is thrown. Otherwise, only an alert is shown.</p><p>Then, in the returned JSX of the <code class="language-text">App</code> component, change how the loading icon and error where shown previously to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><span class="token punctuation">(</span>isLoading <span class="token operator">||</span> mutation<span class="token punctuation">.</span>isLoading<span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token operator"><</span>RefreshIcon className<span class="token operator">=</span><span class="token string">"w-10 h-10 animate-spin mx-auto"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>RefreshIcon<span class="token operator">></span><span class="token punctuation">}</span> <span class="token punctuation">{</span><span class="token punctuation">(</span>isError <span class="token operator">||</span> mutation<span class="token punctuation">.</span>isError<span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token operator"><</span>span className<span class="token operator">=</span><span class="token string">'text-red'</span><span class="token operator">></span><span class="token punctuation">{</span>error <span class="token operator">?</span> <span class="token punctuation">(</span>error<span class="token punctuation">.</span>message <span class="token operator">?</span> error<span class="token punctuation">.</span>message <span class="token operator">:</span> error<span class="token punctuation">)</span> <span class="token operator">:</span> mutation<span class="token punctuation">.</span>error<span class="token punctuation">.</span>message<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><span class="token punctuation">}</span></code></pre></div><p>This shows the loading icon or the error message for both the query that fetches the notes and the mutation that handles deleting a note.</p><p>Finally, find the delete button of a note and add an <code class="language-text">onClick</code> handler:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>button className<span class="token operator">=</span><span class="token string">'link text-gray-400'</span> onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> mutation<span class="token punctuation">.</span><span class="token function">mutate</span><span class="token punctuation">(</span>note<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>Delete<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span></code></pre></div><p>On click, the mutation responsible for deleting the note is triggered using <code class="language-text">mutation.mutate</code>. You pass it the note to delete which is the current note in a <code class="language-text">map</code> loop.</p><h3 id="test-deleting-a-note">Test Deleting a Note</h3><p>Rerun your server and React app if they're not running. Then, open the website again at <code class="language-text">localhost:3000</code>. Click the Delete link for any of your notes. If the note is deleted successfully, an alert will be shown.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/07/Screen-Shot-2022-07-01-at-2.48.53-PM.png" class="kg-image" alt="React (TanStack) Query Tutorial for Beginners" loading="lazy" width="1006" height="314" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/07/Screen-Shot-2022-07-01-at-2.48.53-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/07/Screen-Shot-2022-07-01-at-2.48.53-PM.png 1000w, https://backend.shahednasser.com/content/images/2022/07/Screen-Shot-2022-07-01-at-2.48.53-PM.png 1006w" sizes="(min-width: 720px) 720px"/></figure><p>After closing the alert, the notes will be fetched again and displayed, if there are any other notes.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/07/Screen-Shot-2022-06-28-at-9.10.04-PM-1.png" class="kg-image" alt="React (TanStack) Query Tutorial for Beginners" loading="lazy" width="1446" height="490" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/07/Screen-Shot-2022-06-28-at-9.10.04-PM-1.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/07/Screen-Shot-2022-06-28-at-9.10.04-PM-1.png 1000w, https://backend.shahednasser.com/content/images/2022/07/Screen-Shot-2022-06-28-at-9.10.04-PM-1.png 1446w" sizes="(min-width: 720px) 720px"/></figure><h2 id="conclusion">Conclusion</h2><p>Using React (TanStack) Query, you can easily handle server data fetching and manipulation on your website with advanced features such as caching and synchronization across your React app.</p><p>Make sure to check out the <a href="https://tanstack.com/query/v4">official documentation</a> to learn more about what you can do with React Query.</p>]]></content:encoded></item><item><title><![CDATA[Beginner's Guide to Kubernetes: Understand the Basics]]></title><description><![CDATA[In this blog, we will discuss what they are, how they are used, what is the workflow they have, and whether every application needs it.]]></description><link>https://blog.shahednasser.com/beginners-guide-to-kubernetes-understand-the-basics/</link><guid isPermaLink="false">Ghost__Post__62d068d44e918d05f353772c</guid><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[Shajith]]></dc:creator><pubDate>Thu, 14 Jul 2022 19:14:54 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/23269b2f0186ef1e0efa7f55bf52c4ab/Beginner-s-Guide-to-Kubernetes--Understand-the-Basics.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/23269b2f0186ef1e0efa7f55bf52c4ab/Beginner-s-Guide-to-Kubernetes--Understand-the-Basics.jpg" alt="Beginner's Guide to Kubernetes: Understand the Basics"/><p>You probably have heard the term Kubernetes, somewhere or the other. K8S is an abbreviated form for Kubernetes, starting with the letter ‘K’, Ending with ‘S’, and has 8 characters between the letters, hence the name.</p><p>In this blog, we will discuss what they are, how they are used, what is the workflow they have, and whether every application needs it.</p><h2 id="what-is-kubernetes">What is Kubernetes?</h2><p>Kubernetes is an open-source project initially developed by Google. It is a container orchestration tool. It can be used using on-premise systems, VMs, and clouds.</p><p>Kubernetes is also provided as a service by many providers like AWS, Azure, and Google, and they are known as Amazon EKS, AKS, and GKE respectively. Each has its specific features.</p><p>I get it, if you were to ask what container orchestration is, Let’s see in short what that means,</p><h3 id="moving-your-application-to-the-internet">Moving your Application to the Internet</h3><p>You have an application on your machine that you want to deploy to the internet. Let’s say that it is Irrespective of what framework you use, or it is just the html, CSS, and js, you may want to host it on a server and map it with a domain.</p><p>One of the most common ways to do that is to use a VM and copy those files over there, use Nginx or apache or anything of your preference, start a server, and map the server with a domain name.</p><h3 id="virtual-machines">Virtual Machines</h3><p>VM is one of the first choices in hosting your applications for specific cases. Now, hoping your web application gets popular, how much do you think a VM can accommodate on its server? A VM is simply a computer, RAM, ROM, CPU, etc resources are fixed.</p><p>To imagine, you can think of the number of people who can use your computer simultaneously. Likewise, how will the performance be when so many users access the website at the same time? And this is dependent on the resources of the machine.</p><p>If you have higher resources, it can accommodate a lot of users and less if it has lesser resources.</p><p>These are some of the questions that arise when a website is moved to production, including how many resources you need in your case, which shows higher performance, etc... Setting up a new VM is costly since it is almost an independent machine like the one you're building these with.</p><p>Also, it is a tedious task to create, monitor, and manage multiple instances of the same and redirect them if one is busy.</p><p>These are a few problems that may arise when on a VM. Since a VM is a complete structure, it has numerous packages, OS, and many other dependencies, which are irrelevant for the application to run. Also, the resources can not be used effectively since there is no proper allocation and utilization. That is where containers arise.</p><h3 id="containers">Containers</h3><p>Containers are executable software applications that contain everything it needs to run on their own. Unlike VM, containers are smaller packages and so transporting them is easier. They can also be increased in number or decreased effortlessly. This is one of the important aspects of Kubernetes.</p><p>In an application, there can be several micro-services that help the function of the app. In that case, every micro-service will be made as a container and you can see from this that, as the complexity and size of the application increases, you have to manage multiple containers. Here is where Kubernetes comes in.</p><h3 id="container-orchestration-tool">Container Orchestration tool</h3><p>Kubernetes is a container orchestration tool, which means you get to increase, decrease, destroy, create, and configure containers with higher specifications and much more.</p><p>These help in scalability, monitoring, Health-checks and many more. Let’s see a real-time example of how container orchestration helps.</p><h2 id="short-overview-of-a-real-time-application">Short overview of a Real-time application</h2><p>You developed a full-stack application. It will probably have a Front-end facing application, a backend, and a database.</p><p>Databases should be configured to be updated simultaneously in all the instances if we were to increase them in number, to avoid corruption of data, which again is not easier.</p><p>A database can be deployed in Kubernetes as a stateful set, but that needs a few extra configurations. There are many other different approaches other than Kubernetes for databases. Here in this blog, we will just focus on the front-end and back-end.</p><h3 id="containerizing-the-applications">Containerizing the applications</h3><p>Using docker you will probably have to create a docker file and write configurations in YAML so that the front-end can serve. Nginx or apache servers are generally used for front-end containers but there are many different ways as well. Similarly, a backend container is created.</p><p>Now that you have a front-end container and a back-end container, you want to take the images of both containers and push them to an image repository.</p><h3 id="pushing-the-container-images">Pushing the container images</h3><p>An image repository is generally provided by the cloud provider but Docker has its repository as well, and there are many different other image repositories available, you can choose one of your choices.</p><p>Now, you can add continuous integration and a continuous delivery pipeline in it and deliver the container images to Kubernetes or, you can send them to it directly as well. Continuous integration and continuous delivery pipeline is a different topic, you can learn about them separately and it is independent of Kubernetes.</p><p>Now that the image is pushed to Kubernetes, the image will be built and the container will run.</p><p>Now zooming out, let’s know some terms and structure of Kubernetes.</p><h2 id="structure-of-kubernetes-and-its-terms">Structure of Kubernetes and its terms</h2><h3 id="what-are-pods-and-nodes-in-kubernetes">What are Pods and Nodes in Kubernetes?</h3><p>A pod is a basic deployment on which your container runs. A pod can have multiple containers but generally, a pod per container is preferred.</p><p>A node can be a physical machine or virtual machine and it is where the pods are deployed. A cluster can have several nodes on them.</p><p>The order is like this: container < pod < node < cluster.</p><p>We can start the pod by mentioning how many replicas we want, how many maximum replicas it can have, auto-scaling, health-check, etc.</p><p>The health-check feature checks whether a pod is healthy (running ) and if not, it will pass the information that can be made to create a new pod or inform the user about it for handling. So even if one pod fails, it will automatically detect it and can be made to create further replicas. This is mostly done with zero downtime.</p><h3 id="what-is-downtime">What is downtime?</h3><p>It is the time duration, in which the server is neither accessible nor working.</p><p>Zero Downtime is something that is preferred everywhere. We all know how it is when the site we use most often is down for maintenance or because the server crashed.</p><p>To prevent this and enhance the user experience, Zero downtime is a requirement nowadays.</p><p>Kubernetes helps in 0 downtime - Until a healthy pod starts, the new pod will not destroy itself. This way during updates you can have zero downtime, and also if some pod fails, It can be made to create replicas, etc…</p><h2 id="who-needs-kubernetes">Who needs Kubernetes?</h2><p>Not every application needs Kubernetes, that said every product can have Kubernetes with its features if required. Kubernetes can help your application in many different ways but you probably can analyze different problems like resource management, downtime issues, scaling issues, and feasibility.</p><p>If you need to monitor and automate a large number of containers (micro-services), Kubernetes comes in handy. It does have different other features, which in case required for your product, you can use Kubernetes.</p><h2 id="conclusion">Conclusion</h2><p>K8s is a container orchestration tool and it is used when there is an increased number of containers which can be difficult to monitor and handle. Not every application requires it, you can choose it if the features match your requirement.</p><p>A pod is a basic deployment that can be configured using YAML, the containers are deployed on pods and these pods are located on nodes, where nodes are created on clusters. It is better to know all the features of Kubernetes and match them with your application requirements, before implementing it.</p><p>For a large-scale application, Kubernetes saves a lot of time and automates almost everything related to scaling and everything with zero downtime.</p>]]></content:encoded></item><item><title><![CDATA[How to Create and Deploy a Documentation Website With Docusaurus and Netlify]]></title><description><![CDATA[In this tutorial, you'll learn how to create and deploy documentation with Docusaurus and Netlify.]]></description><link>https://blog.shahednasser.com/how-to-create-and-deploy-a-documentation-website-with-docusaurus-and-netlify/</link><guid isPermaLink="false">Ghost__Post__627f9c2839840e1ac2875259</guid><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 16 May 2022 10:29:16 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/4bceefeacc54e38721d0491696b87d19/How-to-Create-and-Deploy-a-Documentation-Website-With-Docusaurus-and-Netlify.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/4bceefeacc54e38721d0491696b87d19/How-to-Create-and-Deploy-a-Documentation-Website-With-Docusaurus-and-Netlify.jpg" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify"/><p>Documentation websites are used to help people learn about your product or solution. More specifically for developers, it's an important resource to help other developers learn more about your tool and understand better how to use it.</p><p>In this tutorial, you'll learn how to create documentation with <a href="https://docusaurus.io">Docusaurus</a>. This documentation website will have features such as multi-language code blocks and local search. You'll then deploy the website with Netlify.</p><h2 id="prerequisites">Prerequisites</h2><p>Docusaurus requires Node.js version 14.3 or above. If you don't have Node.js installed you can install it from <a href="https://nodejs.org/en/">their website</a>.</p><p>To deploy your docusaurus website, you'll need a <a href="https://github.com">GitHub</a> and <a href="https://www.netlify.com">Netlify</a> accounts. You must also have an empty repository to hold the code of your docusaurus website.</p><h2 id="project-installation">Project Installation</h2><p>Start by creating a new Docusaurus project with the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-docusaurus@latest my-docs classic</code></pre></div><p>This will install Docusaurus in the directory <code class="language-text">my-docs</code> and it will use the <code class="language-text">classic</code> template.</p><p>Now, change to the directory <code class="language-text">my-docs</code> and start the Docusaurus server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> my-docs <span class="token function">npm</span> start</code></pre></div><p>This will start the server on <code class="language-text">localhost:3000</code> and should open the website automatically in your browser.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-2.29.50-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="2852" height="1528"/></figure><p>The code for the landing page is in <code class="language-text">src/pages/index.js</code>. However, this tutorial only focuses on the documentation part.</p><p>To open the documentation, click on Tutorial in the Navigation bar. You'll see a few documentation pages created by default with Docusaursus.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-2.30.00-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="2864" height="1600"/></figure><p>Documentation pages reside in the <code class="language-text">docs</code> directory of your docusaurus project. They are either MD or MDX files. MD files are basic Markdown files with Markdown syntax. MDX files are Markdown files that also support React syntax within.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-2.30.16-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="638" height="186"/></figure><p>Try to change the content of <code class="language-text">intro.md</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="md"><pre class="language-md"><code class="language-md"><span class="token front-matter-block"><span class="token punctuation">---</span> <span class="token front-matter yaml language-yaml">sidebar_position: 1</span> <span class="token punctuation">---</span></span> <span class="token title important"><span class="token punctuation">#</span> Introduction</span> I've changed the documentation!</code></pre></div><p>If the server is still running and you go back to the website, you'll see that the content of the page has changed.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-2.31.08-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="2858" height="982"/></figure><p>Notice that there are at the top of the markdown file three dashes followed by some key-value properties, then followed again by 3 dashes. These are Markdown front matter fields that provide customization to some meta data attributes of the document such as the page title or, in this case, its position in the sidebar.</p><h2 id="create-a-new-document">Create a New Document</h2><p>To create a new document, you need to create a new file under the <code class="language-text">docs</code> directory.</p><p>In this section, you'll create an MDX file to showcase and add some MDX features later in this tutorial.</p><p>Create <code class="language-text">tabs.mdx</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="md"><pre class="language-md"><code class="language-md"><span class="token title important"><span class="token punctuation">#</span> How to Use Tabs</span></code></pre></div><p>This will add a heading to the page. If you check your documentation website, you should find a new link in the sidebar for the new page.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-2.33.25-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="586" height="352"/></figure><p>Let's rearrange the position of the link in the sidebar. Add the following at the top of <code class="language-text">tabs.mdx</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="md"><pre class="language-md"><code class="language-md"><span class="token front-matter-block"><span class="token punctuation">---</span> <span class="token front-matter yaml language-yaml">sidebar_position: 2</span> <span class="token punctuation">---</span></span></code></pre></div><p>This will move "How to Use Tabs" right after "Introduction".</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-3.32.43-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="584" height="318"/></figure><h2 id="optional-features">Optional Features</h2><p>This section includes optional features you can make use of in your documentation. You can skip this section or any subsection if you don't find them necessary for you.</p><h3 id="use-tabs">Use Tabs</h3><p>Using MDX provides you with a lot of features in your Markdown files. One of those features is adding tabs to your page.</p><p>In <code class="language-text">tabs.mdx</code> add the following after the frontmatter part you added earlier:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="jsx"><pre class="language-jsx"><code class="language-jsx"><span class="token keyword">import</span> Tabs <span class="token keyword">from</span> <span class="token string">'@theme/Tabs'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> TabItem <span class="token keyword">from</span> <span class="token string">'@theme/TabItem'</span><span class="token punctuation">;</span></code></pre></div><p>Then, after the heading of the page, add the following to add tabs to the page:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="jsx"><pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Tabs</span></span> <span class="token attr-name">groupId</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>tabs<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">TabItem</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>tab1<span class="token punctuation">"</span></span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Tab 1<span class="token punctuation">"</span></span> <span class="token attr-name">default</span><span class="token punctuation">></span></span><span class="token plain-text"> I like tab 1 </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">TabItem</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">TabItem</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>tab2<span class="token punctuation">"</span></span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Tab 2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"> I like tab 2 </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">TabItem</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Tabs</span></span><span class="token punctuation">></span></span></code></pre></div><p>This will add 2 tabs with each having different text. Notice the following:</p><ol><li>The <code class="language-text">groupId</code> prop on <code class="language-text">Tabs</code> allows you to synchronize the choice of tab throughout the website.</li><li>Each tab item must have a <code class="language-text">value</code> prop. If you want to synchronize the choice of tab throughout the website, you'll need to use the same value for tabs used in other locations (you'll see an example in a bit).</li><li>The <code class="language-text">default</code> prop makes a tab selected by default when the page is first opened.</li></ol><p>Open the documentation now and you'll see tabs added to the documentation. You can click between the tabs and the text will change.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-3.36.34-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="838" height="264"/></figure><p>Let's try adding another <code class="language-text">Tab</code> component under the previous one:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="jsx"><pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Tabs</span></span> <span class="token attr-name">groupId</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>tabs<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">TabItem</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>tab1<span class="token punctuation">"</span></span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Tab 1<span class="token punctuation">"</span></span> <span class="token attr-name">default</span><span class="token punctuation">></span></span><span class="token plain-text"> I still like tab 1 </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">TabItem</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">TabItem</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>tab2<span class="token punctuation">"</span></span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Tab 2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"> I still like tab 2 </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">TabItem</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Tabs</span></span><span class="token punctuation">></span></span></code></pre></div><p>Notice that <code class="language-text">Tabs</code> has the same <code class="language-text">groupId</code> as the previous <code class="language-text">Tabs</code> element, and the tab items have the same values as well.</p><p>If you open the website now you'll see two tabs components each with tab items and text. Try choosing a tab from either component and the choice will be synced with the other tab component as well.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/ezgif.com-gif-maker-2.gif" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="600" height="500"/></figure><h3 id="multi-language-code-blocks">Multi-Language Code Blocks</h3><p>You can also utilize tabs to add code blocks with multiple languages. This is helpful if you want to show the same code block in multiple languages.</p><p>Below the previous tabs you added add this new tab component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="jsx"><pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Tabs</span></span> <span class="token attr-name">groupId</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>code-tabs<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">TabItem</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>js<span class="token punctuation">"</span></span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>JavaScript<span class="token punctuation">"</span></span> <span class="token attr-name">default</span><span class="token punctuation">></span></span><span class="token plain-text"> ```js console.log("Hello") ``` </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">TabItem</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">TabItem</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>python<span class="token punctuation">"</span></span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Python<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"> ```py print("Hello") ``` </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">TabItem</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Tabs</span></span><span class="token punctuation">></span></span></code></pre></div><p>Notice the following:</p><ul><li>This <code class="language-text">Tabs</code> component has a different value for <code class="language-text">groupId</code> compared to previous tabs. That's because there's no need for synchronization between this <code class="language-text">Tabs</code> component and previous components.</li><li>The code blocks inside tabs must be surrounded by empty lines. Otherwise, they will not be rendered properly.</li><li>The indentation for the code blocks should not be more than one tab (equivalent to 2 spaces) or it might not render properly.</li></ul><p>If you open the website now, you'll see tabs for the code blocks.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-2.36.12-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="1694" height="314"/></figure><h3 id="add-automatic-npm-and-yarn-tabs">Add Automatic NPM and Yarn Tabs</h3><p>NPM and Yarn are common package managers used for Node.js-related projects and tools. A lot of times, you want to show the same command in both NPM and Yarn. However, it's a hassle to manually add tabs each time you want to do it.</p><p>In this case, you can make use of the <a href="https://docusaurus.io/docs/markdown-features/code-blocks#npm2yarn-remark-plugin">npm2yarn remark plugin</a>. This plugin will allow you to automatically convert all code blocks that use NPM to yarn on your documentation.</p><p>Start by installing the npm2yarn plugin:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> @docusaurus/remark-plugin-npm2yarn</code></pre></div><p>Then, in <code class="language-text">docusarus.config.js</code> you need to add a new option <code class="language-text">remarkPlugins</code> in the <code class="language-text">config</code> object:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> config <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token comment">//other options...</span> <span class="token literal-property property">presets</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">[</span> <span class="token string">'classic'</span><span class="token punctuation">,</span> <span class="token comment">/** @type {import('@docusaurus/preset-classic').Options} */</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">docs</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">//other options...</span> <span class="token literal-property property">remarkPlugins</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">[</span><span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'@docusaurus/remark-plugin-npm2yarn'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">sync</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div><p>The <code class="language-text">{sync: true}</code> option enables synchronizing the user's choice of tab across the website, similar to the behavior you saw earlier with Tabs.</p><p>Now, in <code class="language-text">tabs.mdx</code> add the following at the end:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="md"><pre class="language-md"><code class="language-md"><span class="token code"><span class="token punctuation">```</span><span class="token code-language">bash npm2yarn</span> <span class="token code-block language-bash"><span class="token function">npm</span> <span class="token function">install</span> react</span> <span class="token punctuation">```</span></span></code></pre></div><p>The important bit here is <code class="language-text">npm2yarn</code>. If you want a code block to have "npm" and "Yarn" tabs and you want to convert the command to yarn, add this keyword after the first 3 backticks of your code block.</p><p>Start your server again and open the website now on the "How to Use Tabs" documentation page. You might need to perform a hard refresh to clear your website's cache.</p><p>If you scroll down you should see the code block you added but with 2 tabs "npm" and "Yarn". You'll also see that the command was automatically converted to a Yarn command under the Yarn tab.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-2.57.37-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="1726" height="320"/></figure><h3 id="table-of-content">Table of Content</h3><p>The last feature you'll learn about in MDX files is the table of content. You can automatically generate a table of content for any page.</p><p>In <code class="language-text">tabs.mdx</code> under the previous imports add a new import:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="jsx"><pre class="language-jsx"><code class="language-jsx"><span class="token keyword">import</span> TOCInline <span class="token keyword">from</span> <span class="token string">'@theme/TOCInline'</span><span class="token punctuation">;</span></code></pre></div><p>Then, add the following under the heading of the page:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="md"><pre class="language-md"><code class="language-md"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>TOCInline</span> <span class="token attr-name">toc</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span>{toc}</span> <span class="token punctuation">/></span></span> <span class="token title important"><span class="token punctuation">##</span> Heading 2</span> <span class="token title important"><span class="token punctuation">###</span> Heading 3</span></code></pre></div><p>If you open the website now, you'll see an automatically generated table of content under the header on the "How to Use Tabs" page.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-3.26.58-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="514" height="228"/></figure><p>Note that the <code class="language-text">TOCInline</code> component will only render headings starting from <code class="language-text">h2</code> or <code class="language-text">##</code>. It will not render <code class="language-text">h1</code> or <code class="language-text">#</code> headings.</p><h2 id="add-search">Add Search</h2><p>An important functionality in any documentation is a search engine. In Docusaurus, you can utilize services like <a href="https://docusaurus.io/docs/search#using-algolia-docsearch">Algolia</a> to add a search engine. However, in this tutorial, you'll add a local search engine that works well for small documentation.</p><p>In your terminal, run the following command to install the plugin:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> --save @easyops-cn/docusaurus-search-local</code></pre></div><p>Then, in <code class="language-text">docusaurus.config.js</code> add to the <code class="language-text">config</code> object a new key <code class="language-text">themes</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token literal-property property">themes</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">[</span> require<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">"@easyops-cn/docusaurus-search-local"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">hashed</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div><p>That's all you need to add a local search engine. </p><p>The search engine will not work if you use <code class="language-text">npm start</code>. You first need to build the website:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> run build</code></pre></div><p>Then serve the build:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> run serve</code></pre></div><p>Open the website again at <code class="language-text">localhost:3000</code>. You should see a search bar at the right of your navigation bar.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-3.04.56-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="752" height="160"/></figure><p>Try searching for one of the pages you added and you should see the results in the dropdown.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-3.06.07-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="1198" height="514"/></figure><h2 id="customize-sidebar">Customize Sidebar</h2><p>The sidebar at the moment is automatically generated from the files in the <code class="language-text">docs</code> directory. You can, however, manually set the sidebar and items in it.</p><p>To do that, open <code class="language-text">sidebars.js</code> and change the value of the <code class="language-text">sidebars</code> object to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> sidebars <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">tutorialSidebar</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'doc'</span><span class="token punctuation">,</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'intro'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'category'</span><span class="token punctuation">,</span> <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Tutorial'</span><span class="token punctuation">,</span> <span class="token literal-property property">items</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'doc'</span><span class="token punctuation">,</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'tabs'</span><span class="token punctuation">,</span> <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Learn all about tabs'</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div><p>This will change the sidebar to include a link and a collapsable section with one sub-item.</p><p>If you open the website now you should see the sidebar changed.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-3.16.52-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="580" height="412"/></figure><h2 id="change-the-edit-this-page-link">Change the "Edit this page" Link</h2><p>At the end of every document, you'll find an "Edit this page" link. This allows contributors to easily make changes they find necessary and submit a PR to your repository.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-4.03.29-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="322" height="154"/></figure><p>The prefix URL of this page is set in <code class="language-text">docusaurus.config.js</code> under the <code class="language-text">docs</code> object in the <code class="language-text">presets</code> array in the <code class="language-text">config</code> object:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token literal-property property">docs</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">editUrl</span><span class="token operator">:</span> <span class="token string">'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>You should change that to your repository's <code class="language-text">docs</code> directory. For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token string">"https://github.com/shahednasser/docusaurus-tutorial/tree/master/"</span></code></pre></div><p>The URL prefix should be the URL before reaching the <code class="language-text">docs</code> directory.</p><p>You can test this out by committing and pushing your changes to the repository. Then, try clicking the link on any of the documents and a new page will open. It will be the document on GitHub where you can edit it and submit a PR with the changes.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-4.08.39-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="2526" height="1382"/></figure><h2 id="deploy-your-documentation-website">Deploy Your Documentation Website</h2><p>The last step you'll do is deploy the documentation website. Log in to Netlify, then click on "Add new site" and from the dropdown select "Import an existing project".</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-4.10.21-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="540" height="376"/></figure><p>A new page will open to create a new site. You can choose to import the code from multiple websites including GitHub. Click on GitHub.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-3.08.41-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="1482" height="668"/></figure><p>You'll then be asked to give Netlify permissions to your GitHub account if you haven't done that before.</p><p>After you give the necessary permissions, you'll be able to select a repository to deploy. Choose the repository you created for the docusaurus website.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-3.09.04-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="1484" height="312"/></figure><p>On the next page, Netlify will show build and deploy settings. They should be similar to the following:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-4.13.30-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="1444" height="1554"/></figure><p>If all looks good, click on "Deploy site". Netlify will then build and deploy your site which will take a couple of minutes.</p><p>Once the deployment is done and published, you can access the website from the randomly generated domain name. You can find it at the top of your website's dashboard on Netlify.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/05/Screen-Shot-2022-05-14-at-4.14.42-PM.png" class="kg-image" alt="How to Create and Deploy a Documentation Website With Docusaurus and Netlify" loading="lazy" width="1458" height="506"/></figure><p>If you open your website you'll find that it's exactly similar to what you worked on locally with all features working well.</p><h2 id="conclusion">Conclusion</h2><p>In this tutorial, you learned about the different features of Docusaurus documentation, how to add local search, and how to deploy the website on Netlify.</p><p>There's still more to be done with your documentation. Here are some additional steps you can take:</p><ol><li>Learn how to <a href="https://docs.netlify.com/domains-https/custom-domains/">customize your domain name in Netlify</a>.</li><li>Learn how to manage your documentation's <a href="https://docusaurus.io/docs/creating-pages">pages</a> and <a href="https://docusaurus.io/docs/blog">blog</a>.</li><li>Check out <a href="https://docusaurus.io/docs/category/guides">Docusaurus's documentation</a> to learn about all the features you can add to your documentation.</li></ol>]]></content:encoded></item><item><title><![CDATA[Local Storage vs Cookies: What's the Difference?]]></title><description><![CDATA[In this article, you'll learn about some of the main differences between local storage and cookies and which you should choose for your websites.]]></description><link>https://blog.shahednasser.com/localstorage-vs-cookies-whats-the-difference/</link><guid isPermaLink="false">Ghost__Post__626e658e39840e1ac2875199</guid><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 05 May 2022 08:57:19 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/28f50e0a23d8f16f69da75473f01187c/Local-Storage-vs-Cookies-What-s-the-Difference.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/28f50e0a23d8f16f69da75473f01187c/Local-Storage-vs-Cookies-What-s-the-Difference.jpg" alt="Local Storage vs Cookies: What's the Difference?"/><p>Cookies in JavaScript are used to read from and store small data related to the user on the browser.</p><p>Local Storage allows you to also read from and store data related to the user on the browser using JavaScript's <a href="https://developer.mozilla.org/en-US/docs/Web/API/Storage">Storage API</a>.</p><p>In this article, you'll learn about some of the main differences between local storage and cookies and which you should choose for your websites.</p><h2 id="what-are-cookies">What are Cookies?</h2><p>Cookies are pieces of data that are communicated between the server and the browser in the header of requests. This allows the server to learn more information about the user accessing the website but also gives you access in the browser to interact with that data.</p><p>An example of using cookies is storing the user's authentication token when they are logged in. The server needs to have access to that cookie to authenticate the user in later requests and retrieve data or process actions based on who the user is.</p><p>Similarly, as a developer, you'll probably need access to that token to use it for future requests to send to your server. </p><p>Cookies on the client-side (the browser) are natively accessed with <code class="language-text">document.cookies</code>. When you store cookies on the browser, you can make them specific to a path in a domain name and you can add an expiry date for them.</p><h2 id="what-is-the-local-storage">What is the Local Storage?</h2><p>Local Storage is used to read and write data in the browser's storage. The data is persistent and has no expiry date. The data is stored in key-value pairs. The server has no access to the client's local storage.</p><p>An example of using local storage is storing the user's color mode preference (light or dark mode). This piece of information is generally not necessary for the server to know, and is used to ensure that the user's preference is reflected on the website.</p><p>Local storage is specific to the protocol of a domain. So, the information returned for a website with HTTP protocol is different than the information returned for that same website with HTTPS protocol.</p><p>Local storage is accessed using <code class="language-text">window.localStorage</code>. It's a read-only property with methods like <code class="language-text">getItem</code> and <code class="language-text">setItem</code> to access and modify or add data to the local storage.</p><h2 id="what-are-the-differences-between-cookies-and-local-storage">What are the Differences Between Cookies and Local Storage</h2><h3 id="access-on-the-server">Access on the Server</h3><p>As mentioned in the previous sections, the server can access the client's cookies but not the data stored in the client's storage.</p><p>So, in use cases where it's important for the server to have access to a set of data, you should use cookies.</p><h3 id="data-size">Data Size</h3><p>There's a big difference between the size of data that cookies can hold and that of the local storage. For cookies, the maximum size is 4096 bytes, whereas for local storage it's 5MB.</p><p>For that reason, cookies should not be used to store large pieces of data. For example, if you want to store the user's details in the browser then it's best to store them in the local storage.</p><h3 id="data-expiry">Data Expiry</h3><p>Cookies have an expiry date. You can set it to a very far away date, but it still expires. On the other hand, data in the local storage does not expire and will be available any time the user opens your website. The only way to clear local storage is either manually with code or if the user clears their browser storage manually.</p><h3 id="better-api">Better API</h3><p>Unless you're using a JavaScript library to facilitate this, it can be a hassle to read or write cookies using <code class="language-text">document.cookies</code> as there is no straight way to do it. Here's an example from <a href="https://www.w3schools.com/js/js_cookies.asp">W3Schools</a> of the code you'd need to use to get and set a cookie by name:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">setCookie</span><span class="token punctuation">(</span><span class="token parameter">cname<span class="token punctuation">,</span> cvalue<span class="token punctuation">,</span> exdays</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> d <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> d<span class="token punctuation">.</span><span class="token function">setTime</span><span class="token punctuation">(</span>d<span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token punctuation">(</span>exdays<span class="token operator">*</span><span class="token number">24</span><span class="token operator">*</span><span class="token number">60</span><span class="token operator">*</span><span class="token number">60</span><span class="token operator">*</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> expires <span class="token operator">=</span> <span class="token string">"expires="</span><span class="token operator">+</span> d<span class="token punctuation">.</span><span class="token function">toUTCString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>cookie <span class="token operator">=</span> cname <span class="token operator">+</span> <span class="token string">"="</span> <span class="token operator">+</span> cvalue <span class="token operator">+</span> <span class="token string">";"</span> <span class="token operator">+</span> expires <span class="token operator">+</span> <span class="token string">";path=/"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">getCookie</span><span class="token punctuation">(</span><span class="token parameter">cname</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> name <span class="token operator">=</span> cname <span class="token operator">+</span> <span class="token string">"="</span><span class="token punctuation">;</span> <span class="token keyword">let</span> decodedCookie <span class="token operator">=</span> <span class="token function">decodeURIComponent</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>cookie<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> ca <span class="token operator">=</span> decodedCookie<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">';'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span>ca<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> c <span class="token operator">=</span> ca<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>c<span class="token punctuation">.</span><span class="token function">charAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token string">' '</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> c <span class="token operator">=</span> c<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>c<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> c<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span>name<span class="token punctuation">.</span>length<span class="token punctuation">,</span> c<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token string">""</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>As for local storage, it implements the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API">Web Storage API</a> which contains easy-to-use methods to read and write data. Here's an example of setting data in the storage and reading them:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">localStorage<span class="token punctuation">.</span><span class="token function">setItem</span><span class="token punctuation">(</span><span class="token string">'name'</span><span class="token punctuation">,</span> <span class="token string">'Shahed'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//later</span> <span class="token keyword">const</span> name <span class="token operator">=</span> localStorage<span class="token punctuation">.</span><span class="token function">getItem</span><span class="token punctuation">(</span><span class="token string">'name'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre></div><h2 id="which-should-you-choose">Which Should You Choose?</h2><p>From reading the differences and definitions this should be clear. However, to summarize it and make it even clearer:</p><ol><li>If you need to store data that is accessible for both the server and the client, use cookies. Otherwise, use local storage.</li><li>If you need to store larger data, use local storage.</li><li>If you need to store data that does not expire, use local storage.</li><li>If you need easy-to-use methods to access and modify the data stored on the client, use local storage.</li></ol><h2 id="conclusion">Conclusion</h2><p>If you're interested to learn more about cookies and local storage, check out MDN's documentation for <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie">cookies</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage">localStorage</a> for a more thorough explanation of each. </p>]]></content:encoded></item><item><title><![CDATA[How to use Transitions in React 18]]></title><description><![CDATA[In this tutorial, you'll learn more about Transitions in React 18 and see them in action.]]></description><link>https://blog.shahednasser.com/how-to-use-transitions-in-react-18/</link><guid isPermaLink="false">Ghost__Post__6263f18539840e1ac287510b</guid><category><![CDATA[React]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 25 Apr 2022 09:13:48 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/a653d678a3e8e1cde9337a2091d4db0c/How-to-use-Transitions-in-React-18-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/a653d678a3e8e1cde9337a2091d4db0c/How-to-use-Transitions-in-React-18-2.jpg" alt="How to use Transitions in React 18"/><p><a href="https://reactjs.org/blog/2022/03/29/react-v18.html">React 18 came out at the end of March</a> with a bundle of new features. One of these new features is Transitions.</p><p>In this tutorial, you'll learn more about Transitions in React 18 and see them in action.</p><h2 id="definition">Definition</h2><p>You have 2 types of transitions. Urgent transitions and non-urgent transitions.</p><h3 id="urgent-transitions">Urgent Transitions</h3><p>Urgent transitions are transitions that the user needs to see instantly. For example, if the user changes their profile name and saves it, they should be able to see the change in the displayed profile name in the navigation bar.</p><p>Urgent transitions are done the same way you've been setting a state before:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>name<span class="token punctuation">,</span> setName<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handleChange</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setName</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//urgent transition</span> <span class="token punctuation">}</span></code></pre></div><h3 id="non-urgent-transitions">Non-Urgent Transitions</h3><p>Non-urgent transitions are transitions that are ok to be delayed a little. For example, if the user is performing a search, it's ok for the results to appear not so instantly.</p><p>There are 2 ways to start a non-urgent transition. The first one is using the hook <code class="language-text">useTransition</code>: </p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span>useTransition<span class="token punctuation">,</span> useState<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">MyApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>results<span class="token punctuation">,</span> setResults<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>pending<span class="token punctuation">,</span> startTransition<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useTransition</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handleChange</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> tempResults <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token operator">...</span> <span class="token comment">// set results from APIs</span> <span class="token function">startTransition</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setResults</span><span class="token punctuation">(</span>tempResults<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>The hook returns the boolean variable <code class="language-text">pending</code> which indicates whether the transition is active or not. It can be used to show a loading component.</p><p>The hook also returns a function <code class="language-text">startTransition</code> that accepts a callback function in which you set the state. The state will not be set immediately.</p><p>The second way to start a non-urgent transition is using the function <code class="language-text">startTransition</code> imported directly from React:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span>startTransition<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">MyApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>results<span class="token punctuation">,</span> setResults<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handleChange</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> tempResults <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token operator">...</span> <span class="token comment">// set results from APIs</span> <span class="token function">startTransition</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setResults</span><span class="token punctuation">(</span>tempResults<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>This approach does not give you access to a variable like <code class="language-text">isPending</code> to check whether the transition is active or not.</p><p>This approach is mainly available for places in your code when you can't use hooks like <code class="language-text">useTransition</code>.</p><h2 id="usage-example">Usage Example</h2><p>In this example, you'll be creating a number input that accepts a large number of images to be shown. Then, random images will be retrieved using <a href="https://ngneat.github.io/falso/">Falso</a>.</p><p>Start by creating a new React app if you don't have one available:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-react-app my-app</code></pre></div><p>Next, change into the directory <code class="language-text">my-app</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> my-app</code></pre></div><p>Then, install the Falso library:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i @ngneat/falso</code></pre></div><p>Now, open <code class="language-text">src/App.js</code> and change it to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token string">'./App.css'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useTransition <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> randImg <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@ngneat/falso'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>number<span class="token punctuation">,</span> setNumber<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>images<span class="token punctuation">,</span> setImages<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>isPending<span class="token punctuation">,</span> startTransition<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useTransition</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">showImages</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//TODO add transition</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">padding</span><span class="token operator">:</span> <span class="token string">'10px'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span>Images<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>label<span class="token operator">></span>Number <span class="token keyword">of</span> images<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"number"</span> min<span class="token operator">=</span><span class="token string">"1"</span> max<span class="token operator">=</span><span class="token string">"10000"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>number<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setNumber</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">display</span><span class="token operator">:</span> <span class="token string">'block'</span><span class="token punctuation">,</span> <span class="token literal-property property">marginTop</span><span class="token operator">:</span> <span class="token string">'10px'</span><span class="token punctuation">,</span> <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'3rem'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string">"button"</span> onClick<span class="token operator">=</span><span class="token punctuation">{</span>showImages<span class="token punctuation">}</span> style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token literal-property property">marginTop</span><span class="token operator">:</span> <span class="token string">'10px'</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span>Show Images<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>span<span class="token operator">></span>Number selected<span class="token operator">:</span> <span class="token punctuation">{</span>number<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><span class="token operator"><</span>br<span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>span<span class="token operator">></span>Results<span class="token operator">:</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token punctuation">{</span>isPending <span class="token operator">&&</span> <span class="token operator"><</span>span<span class="token operator">></span>Loading<span class="token operator">...</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><span class="token punctuation">}</span> <span class="token punctuation">{</span><span class="token operator">!</span>isPending <span class="token operator">&&</span> images<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">&&</span> images<span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span> </code></pre></div><p>You first create 2 state variables <code class="language-text">number</code> and <code class="language-text">images</code>. You also use <code class="language-text">useTransition</code> which gives you access to <code class="language-text">isPending</code> and <code class="language-text">startTransition</code>.</p><p>In the returned JSX, you show a number input and a button that will later retrieve the images on click.</p><p>Below the input and button, the number entered by the user in the input will be shown. Notice that in the <code class="language-text">onChange</code> event handler for the input the name is updated <strong>urgently. </strong>This will show the number instantly as it is updated by the user.</p><p>Let's test it out now. Run the website server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>This will open the website in your browser. If you try to update the input, you'll notice that the number displayed below it will update instantly.</p><figure class="kg-card kg-video-card"><div class="kg-video-container"><video src="https://backend.shahednasser.com/content/media/2022/04/Screen-Recording-2022-04-23-at-3.45.38-PM.mp4" poster="https://img.spacergif.org/v1/798x692/0a/spacer.png" width="798" height="692" playsinline="" preload="metadata" style="background: transparent url('https://backend.shahednasser.com/content/images/2022/04/media-thumbnail-ember409.jpg') 50% 50% / cover no-repeat;"/><div class="kg-video-overlay"><button class="kg-video-large-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button></div><div class="kg-video-player-container"><div class="kg-video-player"><button class="kg-video-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button><button class="kg-video-pause-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/><rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/></svg></button><span class="kg-video-current-time">0:00</span><div class="kg-video-time">/<span class="kg-video-duration"/></div><input type="range" class="kg-video-seek-slider" max="100" value="0"><button class="kg-video-playback-rate">1×</button><button class="kg-video-unmute-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/></svg></button><button class="kg-video-mute-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/></svg></button><input type="range" class="kg-video-volume-slider" max="100" value="100"/></input></div></div></div></figure><p>Now, let's test the non-urgent transition. In <code class="language-text">showImages</code> replace the <code class="language-text">TODO</code> with the following code:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> imgSources <span class="token operator">=</span> <span class="token function">randImg</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">length</span><span class="token operator">:</span> number<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">url<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>img src<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">?v=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>index<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span> key<span class="token operator">=</span><span class="token punctuation">{</span>index<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">startTransition</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setImages</span><span class="token punctuation">(</span>imgSources<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>This will get the images using the <code class="language-text">falso</code> library and inside <code class="language-text">startTransition</code> with set the <code class="language-text">images</code> state variable.</p><p>Notice that in the returned JSX of the function we use <code class="language-text">isPending</code> to indicate whether to show "Loading..." or not.</p><p>If you try clicking on the button now, the "Loading..." text will show first, and then the images will be shown gradually.</p><figure class="kg-card kg-video-card"><div class="kg-video-container"><video src="https://backend.shahednasser.com/content/media/2022/04/Screen-Recording-2022-04-23-at-4.01.34-PM.mp4" poster="https://img.spacergif.org/v1/794x896/0a/spacer.png" width="794" height="896" playsinline="" preload="metadata" style="background: transparent url('https://backend.shahednasser.com/content/images/2022/04/media-thumbnail-ember441.jpg') 50% 50% / cover no-repeat;"/><div class="kg-video-overlay"><button class="kg-video-large-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button></div><div class="kg-video-player-container"><div class="kg-video-player"><button class="kg-video-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button><button class="kg-video-pause-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/><rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/></svg></button><span class="kg-video-current-time">0:00</span><div class="kg-video-time">/<span class="kg-video-duration"/></div><input type="range" class="kg-video-seek-slider" max="100" value="0"><button class="kg-video-playback-rate">1×</button><button class="kg-video-unmute-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/></svg></button><button class="kg-video-mute-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/></svg></button><input type="range" class="kg-video-volume-slider" max="100" value="100"/></input></div></div></div></figure><h2 id="conclusion">Conclusion</h2><p>Transitions in React 18 allow you to optimize your user experience, especially for tasks or features that require some time to load. You can now use Transitions in React 18 to differentiate between instate updates and updates that can be delayed, and show in the UI any necessary loading more efficiently for those that require more time.</p>]]></content:encoded></item><item><title><![CDATA[How to Create a Blog with Stackbit and Next.js]]></title><description><![CDATA[In this tutorial, you'll learn how to create a blog with Stackbit using its Next.js starter theme.]]></description><link>https://blog.shahednasser.com/how-to-create-a-blog-with-stackbit-and-next-js/</link><guid isPermaLink="false">Ghost__Post__625ae7a439840e1ac2874f85</guid><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 20 Apr 2022 08:10:59 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/da978a60198d62ff80ba9549febf0484/How-to-Create-a-Blog-with-Stackbit-and-Next.js-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/da978a60198d62ff80ba9549febf0484/How-to-Create-a-Blog-with-Stackbit-and-Next.js-2.jpg" alt="How to Create a Blog with Stackbit and Next.js"/><p><a href="https://www.stackbit.com">Stackbit</a> is a website builder that gives both technical and non-technical people a lot of power when creating their websites. It can be used to create portfolio websites, blogs, or any type of website if you wish to extend it to your use case.</p><p>In this tutorial, you'll learn how to create a blog with Stackbit using its Next.js starter theme. You'll also learn how to add custom pages for Content Models by creating an Authors page.</p><h2 id="project-setup">Project Setup</h2><p>Start by <a href="https://app.stackbit.com/create/theme">choosing one of the Starter theme</a>. This tutorial will be focused on the <a href="https://starter-nextjs.stackbit.app"/><a href="https://starter-nextjs.stackbit.app">Starter th</a>eme.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-7.03.36-PM.png" class="kg-image" alt="How to Create a Blog with Stackbit and Next.js" loading="lazy" width="2674" height="1638"/></figure><p>Then, choose a name for your new project.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-7.03.57-PM.png" class="kg-image" alt="How to Create a Blog with Stackbit and Next.js" loading="lazy" width="1750" height="1510"/></figure><p>If you're not signed in you'll then be asked to either create an account or sign in. I recommend creating an account with GitHub as it will be easier to connect your repository to it then.</p><p>You'll then have your website ready for customization.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-09-at-6.00.40-PM.png" class="kg-image" alt="How to Create a Blog with Stackbit and Next.js" loading="lazy" width="2880" height="1640"/></figure><p>Notice that your website will be deployed on a free Stackbit subdomain. So, you'll be able to view it online right away.</p><h2 id="transfer-repository-to-your-account">Transfer Repository to Your Account</h2><p>The next step is to transfer the website codebase to your GitHub account. This makes it possible for you to make changes to the website's codebase and add new content models.</p><p>Click on the gear icon at the top left. Then, under "Connected Services" you'll see GitHub and you'll be able to Request Repo Transfer.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-09-at-6.01.32-PM.png" class="kg-image" alt="How to Create a Blog with Stackbit and Next.js" loading="lazy" width="1652" height="342"/></figure><p>When you click on that you'll receive an email to accept the transfer. Once you click on the link in the email, the transfer will begin and might take a couple of minutes.</p><p>Once the transfer is done, you'll have your website's codebase in you GitHub account.</p><h2 id="understanding-the-branches">Understanding the Branches</h2><p>In your GitHub repository, you'll have 2 branches: the <code class="language-text">master</code> branch and the <code class="language-text">preview</code> branch.</p><p>The <code class="language-text">master</code> branch is the deployed version that everyone can see when they go on your website.</p><p>The <code class="language-text">preview</code> branch is what you can see when you log in on Stackbit. Think of it as a draft version. Once you think the changes are ready to be deployed on the main website, you can either push the changes to the master branch manually or just click the "Publish" button at the top right in your Stackbit app.</p><h2 id="set-up-local-development">Set Up Local Development</h2><p>Stackbit has a code editor that you can use right in your Stackbit app by clicking on the code icon in the sidebar.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-17-at-1.24.09-PM.png" class="kg-image" alt="How to Create a Blog with Stackbit and Next.js" loading="lazy" width="1560" height="1402"/></figure><p>Once you make a change in the code, it will be automatically committed to the <code class="language-text">preview</code> branch which is what you see in your Stackbit app.</p><p>Alternatively, you can work on your website's development locally. To do that, click on the gear icon at the top left again. Under "Envoironment" you'll see "Local Development" with steps you can copy and paste into your terminal directly.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-09-at-6.05.11-PM.png" class="kg-image" alt="How to Create a Blog with Stackbit and Next.js" loading="lazy" width="1662" height="510"/></figure><p>Please note that if you haven't transferred the codebase into your GitHub account you won't be able to see these tips.</p><p>As mentioned under "Local Development", once you push commits to the <code class="language-text">preview</code> branch, the visual editor in your Stackbit app will update automatically.</p><h2 id="creating-posts">Creating Posts</h2><p>There are 2 ways to create posts: through the visual editor or through the code editor.</p><h3 id="visual-editor">Visual Editor</h3><p>On your Stackbit app, if you press the second icon "CMS" you'll be able to edit and add pages and blog posts on your website.</p><p>Try clicking on "Post" then "Add new Post". You'll be able to enter information like slug and title. Then, you can select a feature image and the author.</p><p>You can then use the content editor, which has text formatting you can use but also supports raw markdown editing by pressing the Raw MD button.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-09-at-6.40.49-PM.png" class="kg-image" alt="How to Create a Blog with Stackbit and Next.js" loading="lazy" width="2420" height="1640"/></figure><p>All changes you make to posts are automatically committed to the <code class="language-text">preview</code> branch. Once you publish them they'll be live on your deployed website.</p><h3 id="code-editor">Code Editor</h3><p>To add posts in the code editor, go to <code class="language-text">content</code> then <code class="language-text">pages</code>. You'll see all pages there in markdown files, where the names of the files are the slugs of the pages.</p><p>You'll also find a <code class="language-text">blog</code> directory which holds all posts inside it. To add a blog post create a new file with its name the slug you want for the post. Then, add in it the following information:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="markdown"><pre class="language-markdown"><code class="language-markdown"><span class="token front-matter-block"><span class="token punctuation">---</span> <span class="token front-matter yaml language-yaml">title: Test Post layout: PostLayout date: '2021-07-01' author: content/data/team/hugh-saturation.json excerpt: >- Sed in facilisis dui. Nulla molestie risus in mi dapibus, eget porta lorem semper. Donec sed facilisis nibh. featuredImage: type: ImageBlock url: /images/post-2.jpg altText: Post Image bottomSections: - elementId: '' variant: variant-c colors: colors-a title: Read next recentCount: 3 styles: self: height: auto width: wide margin: ['mt-0', 'mb-0', 'ml-0', 'mr-0'] padding: ['pt-12', 'pb-56', 'pr-4', 'pl-4'] justifyContent: center title: textAlign: center subtitle: textAlign: center actions: justifyContent: center type: RecentPostsSection</span> <span class="token punctuation">---</span></span> This is test post </code></pre></div><p>Everything between the opening and closing 3 dashes are the values of the fields you enter in your visual editor. That includes the title, author, feature image, and more.</p><p>Then, after the three dashes is the markdown content of the post. This is the content you'd enter in the text editor in the visual Stackbit app, but it should be in markdown format.</p><p>Once you're done, save the new file and commit it to the <code class="language-text">preview</code> branch. You'll be able to see it in the visual editor among the CMS.</p><p>If you also open the Blog page in your Stackbit app or open the website locally, you should see the post you added among other existing posts.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-09-at-6.18.11-PM.png" class="kg-image" alt="How to Create a Blog with Stackbit and Next.js" loading="lazy" width="924" height="1124"/></figure><h2 id="add-pages-for-authors">Add Pages for Authors</h2><p>In this section, you'll start to customize your Stackbit starter. You'll be adding a new predefined type of page to display authors. You'll need to create a layout specific for that page before creating that page.</p><h3 id="add-page-to-content-models">Add Page to Content Models</h3><p>Open <code class="language-text">stackbit.yaml</code> in the root of your website's code and add the following under <code class="language-text">contentModels</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">contentModels</span><span class="token punctuation">:</span> <span class="token punctuation">...</span> <span class="token key atrule">PersonFeedLayout</span><span class="token punctuation">:</span> <span class="token key atrule">isPage</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> <span class="token key atrule">singleInstance</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> <span class="token key atrule">urlPath</span><span class="token punctuation">:</span> <span class="token string">'/authors'</span> <span class="token key atrule">file</span><span class="token punctuation">:</span> <span class="token string">'authors.md'</span> <span class="token key atrule">newFilePath</span><span class="token punctuation">:</span> <span class="token string">'authors.md'</span></code></pre></div><p>You're adding a new layout <code class="language-text">PersonFeedLayout</code>. You can read more about <a href="https://docs.stackbit.com/reference/stackbit-yaml/mapping-content-models/">content model fields in Stackbit's documentation</a>, but briefly:</p><ol><li>If <code class="language-text">isPage</code> is set to <code class="language-text">true</code> the UI will allow you to create pages using this model.</li><li><code class="language-text">singleInstance</code> means that this page can only be created once.</li><li><code class="language-text">urlPath</code> is the path that this page will be found on.</li><li><code class="language-text">file</code> is the markdown file that holds the data and content for this page. Since this is a page, its path is relative to <code class="language-text">content/pages</code></li><li><code class="language-text">newFilePath</code> is the file that should be created when this page is created through the UI. Similarly, since this content model is a page the path is relative to <code class="language-text">content/pages</code>.</li></ol><h3 id="define-the-content-model-fields">Define the Content Model Fields</h3><p>In this section, you'll define the fields of the new content model <code class="language-text">PersonFeedLayout</code>. This means that when you try to create the page through the UI, these fields is what you will see.</p><p>To do that, create the file <code class="language-text">.stackbit/models/PersonFeedLayout.yaml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">name</span><span class="token punctuation">:</span> PersonFeedLayout <span class="token key atrule">label</span><span class="token punctuation">:</span> Authors <span class="token key atrule">labelField</span><span class="token punctuation">:</span> title <span class="token key atrule">layout</span><span class="token punctuation">:</span> PersonFeedLayout <span class="token key atrule">hideContent</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> <span class="token key atrule">extends</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> Seo <span class="token key atrule">fields</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">type</span><span class="token punctuation">:</span> string <span class="token key atrule">name</span><span class="token punctuation">:</span> title <span class="token key atrule">label</span><span class="token punctuation">:</span> Title <span class="token key atrule">default</span><span class="token punctuation">:</span> This is a page title <span class="token punctuation">-</span> <span class="token key atrule">type</span><span class="token punctuation">:</span> list <span class="token key atrule">name</span><span class="token punctuation">:</span> topSections <span class="token key atrule">label</span><span class="token punctuation">:</span> Top Sections <span class="token key atrule">items</span><span class="token punctuation">:</span> <span class="token key atrule">type</span><span class="token punctuation">:</span> model <span class="token key atrule">groups</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> sectionComponent <span class="token punctuation">-</span> <span class="token key atrule">type</span><span class="token punctuation">:</span> list <span class="token key atrule">name</span><span class="token punctuation">:</span> bottomSections <span class="token key atrule">label</span><span class="token punctuation">:</span> Bottom Sections <span class="token key atrule">items</span><span class="token punctuation">:</span> <span class="token key atrule">type</span><span class="token punctuation">:</span> model <span class="token key atrule">groups</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> sectionComponent <span class="token punctuation">-</span> <span class="token key atrule">type</span><span class="token punctuation">:</span> style <span class="token key atrule">name</span><span class="token punctuation">:</span> styles <span class="token key atrule">styles</span><span class="token punctuation">:</span> <span class="token key atrule">title</span><span class="token punctuation">:</span> <span class="token key atrule">fontWeight</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'400'</span><span class="token punctuation">,</span> <span class="token string">'700'</span><span class="token punctuation">]</span> <span class="token key atrule">fontStyle</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'normal'</span><span class="token punctuation">,</span> <span class="token string">'italic'</span><span class="token punctuation">]</span> <span class="token key atrule">textAlign</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'left'</span><span class="token punctuation">,</span> <span class="token string">'center'</span><span class="token punctuation">,</span> <span class="token string">'right'</span><span class="token punctuation">]</span> <span class="token key atrule">default</span><span class="token punctuation">:</span> <span class="token key atrule">title</span><span class="token punctuation">:</span> <span class="token key atrule">textAlign</span><span class="token punctuation">:</span> center</code></pre></div><p>You can learn more about <a href="https://docs.stackbit.com/reference/defining-models/">Models in Stackbit through their documentation</a>, but briefly the items under <code class="language-text">fields</code> are what you'll see in the UI and the fields you can enter for this content model. This content model has 4 fields:</p><ol><li><code class="language-text">title</code>: the title of the page</li><li><code class="language-text">topSections</code>: Sections you want to add to the top of the page. This is useful if you want to allow users using the visual editor to add custom sections before your defined layout.</li><li><code class="language-text">bottomSections</code>: Similarly to <code class="language-text">topSections</code>, you'll allow users using the visual editor to add custom sections after the defined layout.</li><li><code class="language-text">styles</code>: Allow the users using the visual editor to customize some of the style of the layout. </li></ol><h3 id="create-new-layout">Create New Layout</h3><p>Next, you'll be creating the <code class="language-text">PersonFeedLayout</code> which will hold the implementation of the Authors page.</p><p>Create a new file <code class="language-text">src/components/layouts/PersonFeedLayout/index.tsx</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="jsx"><pre class="language-jsx"><code class="language-jsx"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> ImageBlock <span class="token keyword">from</span> <span class="token string">'../../molecules/ImageBlock'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> getBaseLayoutComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../../../utils/base-layout'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> getComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../../components-registry'</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">PageLayout</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> page<span class="token punctuation">,</span> site <span class="token punctuation">}</span> <span class="token operator">=</span> props<span class="token punctuation">;</span> <span class="token keyword">const</span> BaseLayout <span class="token operator">=</span> <span class="token function">getBaseLayoutComponent</span><span class="token punctuation">(</span>page<span class="token punctuation">.</span>baseLayout<span class="token punctuation">,</span> site<span class="token punctuation">.</span>baseLayout<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> topSections <span class="token operator">=</span> page<span class="token punctuation">.</span>topSections <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">const</span> authors <span class="token operator">=</span> page<span class="token punctuation">.</span>authors <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">const</span> bottomSections <span class="token operator">=</span> page<span class="token punctuation">.</span>bottomSections <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">BaseLayout</span></span> <span class="token attr-name">page</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>page<span class="token punctuation">}</span></span> <span class="token attr-name">site</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>site<span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>main</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>main<span class="token punctuation">"</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sb-layout sb-page-layout<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token punctuation">{</span>page<span class="token punctuation">.</span>title <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-center my-5<span class="token punctuation">"</span></span> <span class="token attr-name">data-sb-field-path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token punctuation">{</span>page<span class="token punctuation">.</span>title<span class="token punctuation">}</span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text"> </span><span class="token punctuation">{</span>topSections<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">data-sb-field-path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sections<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token punctuation">{</span>topSections<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">section<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> Component <span class="token operator">=</span> <span class="token function">getComponent</span><span class="token punctuation">(</span>section<span class="token punctuation">.</span>type<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>Component<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">no component matching the page section's type: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>section<span class="token punctuation">.</span>type<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Component</span></span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>index<span class="token punctuation">}</span></span> <span class="token spread"><span class="token punctuation">{</span><span class="token operator">...</span>section<span class="token punctuation">}</span></span> <span class="token attr-name">data-sb-field-path</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">sections.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>index<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-10 my-16 max-w-screen-md mx-auto<span class="token punctuation">'</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token punctuation">{</span>authors<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">author<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>group text-center<span class="token punctuation">'</span></span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>index<span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token punctuation">{</span>author<span class="token punctuation">.</span>image <span class="token operator">&&</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">ImageBlock</span></span> <span class="token spread"><span class="token punctuation">{</span><span class="token operator">...</span>author<span class="token punctuation">.</span>image<span class="token punctuation">}</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>group-hover:shadow-md transition-shadow rounded-full w-40 h-40 mx-auto<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">}</span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h3</span><span class="token punctuation">></span></span><span class="token punctuation">{</span>author<span class="token punctuation">.</span>firstName<span class="token punctuation">}</span><span class="token plain-text"> </span><span class="token punctuation">{</span>author<span class="token punctuation">.</span>lastName<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h3</span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-gray-500<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token punctuation">{</span>author<span class="token punctuation">.</span>role<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token punctuation">{</span>bottomSections<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">data-sb-field-path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sections<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token punctuation">{</span>bottomSections<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">section<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> Component <span class="token operator">=</span> <span class="token function">getComponent</span><span class="token punctuation">(</span>section<span class="token punctuation">.</span>type<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>Component<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">no component matching the page section's type: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>section<span class="token punctuation">.</span>type<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Component</span></span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>index<span class="token punctuation">}</span></span> <span class="token spread"><span class="token punctuation">{</span><span class="token operator">...</span>section<span class="token punctuation">}</span></span> <span class="token attr-name">data-sb-field-path</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">sections.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>index<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>main</span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">BaseLayout</span></span><span class="token punctuation">></span></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>First, notice that you display the <code class="language-text">topSections</code> first and the <code class="language-text">bottomSections</code> last in your layout.</p><p>In the middle, you display the authors in a grid. The authors are received in the props of the layout. You'll be defining this in the next section.</p><p>After creating this layout, add it in <code class="language-text">src/components/layouts/index.tsx</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> PostFeedLayout <span class="token keyword">from</span> <span class="token string">'./PostFeedLayout'</span><span class="token punctuation">;</span> <span class="token comment">//...</span> <span class="token keyword">export</span> <span class="token punctuation">{</span> <span class="token operator">...</span><span class="token punctuation">,</span> PersonFeedLayout <span class="token punctuation">}</span></code></pre></div><p>Finally, you need to add it to <code class="language-text">src/components/components-registry.ts</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> components <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token comment">//...,</span> <span class="token string-property property">'PersonFeedLayout'</span><span class="token operator">:</span> <span class="token function">dynamic</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'./layouts/PersonFeedLayout'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div><h3 id="add-props">Add Props</h3><p>To define the props passed to this layout, first, go to <code class="language-text">src/utils/data-utils.js</code> and add a new function:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">getAuthors</span><span class="token punctuation">(</span><span class="token parameter">objects</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> objects<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">object</span><span class="token punctuation">)</span> <span class="token operator">=></span> object<span class="token punctuation">.</span>type <span class="token operator">===</span> <span class="token string">'Person'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>The <code class="language-text">sourcebit-target-next</code> plugin will use the <code class="language-text">sourcebit-source-filesystem</code> to read files under <code class="language-text">content</code> and import them into your Stackbit website. </p><p>There are two types of content: pages under the <code class="language-text">content/pages</code> directory and data under <code class="language-text">content/data</code> directory. You'll be able to filter out content based on the <code class="language-text">type</code> field for data content, or the <code class="language-text">layout</code> field for pages content.</p><p>In this case, you're retrieving all authors, which are data content. So, you check if the <code class="language-text">type</code> field is <code class="language-text">Person</code>. Please note that, by default, all authors are under <code class="language-text">content/data/team</code> in JSON files.</p><p>Next, you'll use this function to pass the authors as a prop to the layout you created in the previous section. Go to <code class="language-text">src/utils/static-props-resolvers.js</code> and add the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> <span class="token comment">//...,</span> getAuthors <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./data-utils'</span><span class="token punctuation">;</span> <span class="token comment">//...</span> <span class="token keyword">const</span> StaticPropsResolvers <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token comment">//..,</span> <span class="token function-variable function">PersonFeedLayout</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">props<span class="token punctuation">,</span> data</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token operator">...</span>props<span class="token punctuation">,</span> <span class="token literal-property property">authors</span><span class="token operator">:</span> <span class="token function">getAuthors</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>objects<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div><p>Your Next.js website will resolve the props of the layouts by checking through the <code class="language-text">StaticPropsResolvers</code> object. The key is the name of the layout and the value is a function that returns an object which will be the props of the layout.</p><p>You add a new key for <code class="language-text">PersonFeedLayout</code> which accepts <code class="language-text">props</code> and <code class="language-text">data</code> as parameters. <code class="language-text">props</code> is the data entered by the user in the UI for the fields you created for the content model earlier. For example, the <code class="language-text">bottomSections</code> field.</p><p>The <code class="language-text">data</code> is all the data on your website made available by <code class="language-text">sourcebit-target-next</code> as explained earlier. It is an object that has 3 properties:</p><ol><li> <code class="language-text">objects</code> which is an array of all content files loaded by the <code class="language-text">sourcebit-source-filesystem</code> plugin.</li><li><code class="language-text">pages</code> which is an array holding all static page props.</li><li><code class="language-text">props</code> which is an object with common props for all pages.</li></ol><p>In this function, you return all the props as-is and you add the <code class="language-text">authors</code> prop which will call the <code class="language-text">getAuthors</code> function you created earlier passing it <code class="language-text">data.objects</code>.</p><h3 id="add-the-authors-page">Add the Authors Page</h3><p>Finally, you just need to add the Authors page. Create the file <code class="language-text">content/pages/authors.md</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="markdown"><pre class="language-markdown"><code class="language-markdown"><span class="token front-matter-block"><span class="token punctuation">---</span> <span class="token front-matter yaml language-yaml">title: Authors layout: PersonFeedLayout topSections: - type: CtaSection elementId: '' colors: colors-a backgroundSize: full title: Let's do this text: >- The Stackbit theme is flexible and scalable to every need. It can manage any layout and any screen. actions: - type: Button label: Try it now url: / style: primary backgroundImage: null styles: self: height: auto width: narrow margin: - mt-0 - mb-0 - ml-0 - mr-0 padding: - pt-24 - pb-24 - pl-4 - pr-4 alignItems: center justifyContent: center flexDirection: col title: textAlign: left text: textAlign: left actions: justifyContent: flex-start</span> <span class="token punctuation">---</span></span> </code></pre></div><p>This defines the page to use the <code class="language-text">PersonFeedLayout</code> and adds among its top sections a Call to Action (CTA) section.</p><p>If you run your server now:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> run dev</code></pre></div><p>and go to <code class="language-text">/authors</code>, you'll be able to see all the authors in your blog.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-17-at-2.24.40-PM.png" class="kg-image" alt="How to Create a Blog with Stackbit and Next.js" loading="lazy" width="2252" height="1368"/></figure><p>If you push the changes to the <code class="language-text">preview</code> branch you'll be able to see your new page in the Stackbit app as well as edit the page fields.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-17-at-2.25.29-PM.png" class="kg-image" alt="How to Create a Blog with Stackbit and Next.js" loading="lazy" width="1990" height="1472"/></figure><h3 id="add-link-to-page-in-the-header">Add Link to Page in the Header</h3><p>Optionally, you can add a link to the page in the header. To do that, open <code class="language-text">content/data/config.json</code> and add the new link under <code class="language-text">primaryLinks</code> in <code class="language-text">header</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> ...<span class="token punctuation">,</span> <span class="token property">"header"</span><span class="token operator">:</span> <span class="token punctuation">{</span> ...<span class="token punctuation">,</span> <span class="token property">"primaryLinks"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ...<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"Link"</span><span class="token punctuation">,</span> <span class="token property">"label"</span><span class="token operator">:</span> <span class="token string">"Authors"</span><span class="token punctuation">,</span> <span class="token property">"altText"</span><span class="token operator">:</span> <span class="token string">"Authors"</span><span class="token punctuation">,</span> <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"/authors"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>If you save the changes and view the website in local development, or push the changes to the <code class="language-text">preview</code> branch to view it on the Stackbit app, you'll see a new link the navigation bar for "Authors".</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-09-at-6.44.22-PM.png" class="kg-image" alt="How to Create a Blog with Stackbit and Next.js" loading="lazy" width="2702" height="1588"/></figure><h2 id="conclusion">Conclusion</h2><p>In this tutorial, you learned how you can set up Stackbit and do some development and customization on it. For more features, be sure to check out <a href="https://docs.stackbit.com">Stackbit's documentation</a> for more details.</p>]]></content:encoded></item><item><title><![CDATA[10+ Awesome Islamic Tools and Projects]]></title><description><![CDATA[As we are halfway through Ramadan, I want to take a chance to shed light on some cool Islamic tools and projects. ]]></description><link>https://blog.shahednasser.com/10-awesome-islamic-tools-and-projects/</link><guid isPermaLink="false">Ghost__Post__625ad95c39840e1ac2874ea3</guid><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 18 Apr 2022 09:27:54 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/536816f1ec08d643b496e09903988f82/10--Awesome-Islamic-Tools-and-Projects.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/536816f1ec08d643b496e09903988f82/10--Awesome-Islamic-Tools-and-Projects.jpg" alt="10+ Awesome Islamic Tools and Projects"/><p>As we are halfway through Ramadan, I want to take a chance to shed light on some cool Islamic tools and projects. </p><p>Some of these are open source and you can use them in your own projects as well.</p><h2 id="al-quran-cloud">Al Quran Cloud</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.03.31-PM.png" class="kg-image" alt="10+ Awesome Islamic Tools and Projects" loading="lazy" width="2380" height="1246"/></figure><p><a href="https://alquran.cloud">Al Quran Cloud</a> is a web app that you can use to read Quran, listen to it with your favorite reciters, and check translations in many languages.</p><p>What's cooler about this project is that it provides free APIs that you can use to add Quran verses to your own projects. You can use it to add the Quran verses both are text and audio, as well as display translations of it.</p><p>I personally have utilized these APIs in my Chrome extension <a href="https://chrome.google.com/webstore/detail/quran-in-new-tab/hggkcijghhpkdjeokpfgbhnpecliiijg?hl=en">Quran in New Tab.</a></p><p>You can also support this project on <a href="https://github.com/islamic-network/alquran.cloud">GitHub</a>.</p><h2 id="salat-vue">Salat Vue</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.07.41-PM.png" class="kg-image" alt="10+ Awesome Islamic Tools and Projects" loading="lazy" width="1150" height="1178"/></figure><p><a href="https://salat-vue.netlify.app">Salat Vue</a> is a simple Web app that shows you prayer times in any country and city. It also shows you the next prayer and how much time is left remaining.</p><p>You can support this tool on <a href="https://github.com/ELATTARIYassine/Salat-vue">GitHub</a>.</p><h2 id="hijri-date">hijri-date</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.09.00-PM.png" class="kg-image" alt="10+ Awesome Islamic Tools and Projects" loading="lazy" width="2112" height="870"/></figure><p><a href="https://abdennour.github.io/hijri-date/">hijri-date</a> is an NPM package that you can use to get the Hijri date. It provides a <code class="language-text">HijriDate</code> class that you can use to handle hijri dates with an API similar to JavaScript's Date. You can also use it to convert to Gregorian date and vice versa.</p><p>You can support this tool on <a href="https://github.com/abdennour/hijri-date">GitHub</a>.</p><h2 id="qurancom">Quran.com</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.12.49-PM.png" class="kg-image" alt="10+ Awesome Islamic Tools and Projects" loading="lazy" width="2760" height="962"/></figure><p><a href="https://quran.com">Quran.com</a> is an organization that provides web apps and mobile apps to easily have access to the Quran and read it, as well as listen to it. It's actively maintained and uses modern technologies.</p><p>You can support this project on <a href="https://github.com/quran">GitHub</a>. You can also <a href="https://donate.quran.com">donate to their organization</a> for more support.</p><h2 id="azkar-db">azkar-db</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.15.38-PM.png" class="kg-image" alt="10+ Awesome Islamic Tools and Projects" loading="lazy" width="2504" height="1058"/></figure><p><a href="https://github.com/osamayy/azkar-db">azkar-db</a> is a GitHub repository that has a wide set of azkar in a SQLite database, JSON format, and CSV format. It includes Morning azkar and Evening azkar, as well as other types.</p><p>Unfortunately, this one is all in Arabic only.</p><h2 id="muslim-mate">Muslim Mate</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.25.23-PM.png" class="kg-image" alt="10+ Awesome Islamic Tools and Projects" loading="lazy" width="2758" height="1534"/></figure><p><a href="http://muslimmate.islam-db.com">Muslim Mate</a> is a dashboard with the necessary information for Muslims. It includes prayer times, a calendar of Islamic events, Azkar, and weather stats among other things. It's available as a website and as an Android app.</p><p>It's also fully customizable as you can remove or change the places of items in your dashboard.</p><p>You can support this project on <a href="https://github.com/fekracomputers/MuslimMateWebsite">GitHub</a>.</p><h2 id="al-adhan">Al-Adhan</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.30.14-PM.png" class="kg-image" alt="10+ Awesome Islamic Tools and Projects" loading="lazy" width="2338" height="1542"/></figure><p>By the creator of Al Quran Cloud, <a href="https://aladhan.com">this website</a> provides you with information about prayer times, as well as a Hijri calendar with events.</p><p>This project also has a free API that you can use in your projects. You can use it to get the Hijri calendar of a Gregorian month, prayer times at a specific longitude and latitude, and much more.</p><p>You can support this project and contribute to it on <a href="https://github.com/islamic-network/api.aladhan.com">GitHub</a>.</p><h2 id="quran-flutter">Quran-Flutter</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.34.13-PM.png" class="kg-image" alt="10+ Awesome Islamic Tools and Projects" loading="lazy" width="1756" height="1102"/></figure><p><a href="https://github.com/SadaqaWorks/Quran-Flutter">Quran-Flutter</a> is an open-source flutter project that allows you to read the Quran cross-platforms. This project is still in its development phase but at the moment it's a responsive Quran reader for any device.</p><h2 id="its-salah-time">It's Salah Time</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-17-at-6.29.51-PM.png" class="kg-image" alt="10+ Awesome Islamic Tools and Projects" loading="lazy" width="608" height="1418"/></figure><p><a href="https://its-salah-time.vercel.app/">It's Salah Time</a> is a beautiful web app that shows you prayer times based on your location. It's also a PWA so you can add it to your mobile device and view it as an app.</p><p>You can support and contribute to this project on <a href="https://github.com/murtuzaalisurti/salah">GitHub</a>.</p><h2 id="sunnahcom">Sunnah.com</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.44.58-PM.png" class="kg-image" alt="10+ Awesome Islamic Tools and Projects" loading="lazy" width="2796" height="1272"/></figure><p><a href="https://sunnah.com">Sunnah.com</a> is a website you can use to view the Hadith of Prophet Muhammad. You can also search for it. It supports 3 languages: Arabic, English, and Urdu.</p><p>It also provides <a href="https://sunnah.api-docs.io/1.0/getting-started/introduction">free-to-use APIs</a> to use these resources in your projects.</p><p> You can support and contribute to them on <a href="https://github.com/sunnah-com/api">GitHub</a>.</p><h2 id="pyislam">pyIslam</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.50.29-PM.png" class="kg-image" alt="10+ Awesome Islamic Tools and Projects" loading="lazy" width="2066" height="1548"/></figure><p>pyIslam is a Python library that you can use to calculate prayer times, hijri dates, qiblad direction, Zakat calculation, and more.</p><p>You can support and contribute to the project on <a href="https://github.com/abougouffa/pyIslam">GitHub</a>.</p><h2 id="quran-cli">Quran CLI</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/screen1.png" class="kg-image" alt="10+ Awesome Islamic Tools and Projects" loading="lazy" width="724" height="597"/></figure><p><a href="https://github.com/sarfraznawaz2005/quran-cli">Quran CLI</a> is an NPM package that you can install locally by cloning the GitHub repository. It allows you to view the Quran right from your terminal.</p><p>You can read as well as search the Quran right from your CLI. You can view the verses in both English and Arabic.</p><h2 id="more-awesome-tools">More Awesome Tools</h2><p>To check out more awesome Islamic tools, check out the following repositories:</p><ol><li><a href="https://github.com/AhmedKamal/awesome-Islam">Awesome-Islam</a></li><li><a href="https://github.com/choubari/Awesome-Muslims">Awesome-Muslims</a></li></ol>]]></content:encoded></item><item><title><![CDATA[How to Install Python 2 on macOS 12.3+]]></title><description><![CDATA[Learn how to install Python 2 on macOS 12.3+]]></description><link>https://blog.shahednasser.com/how-to-install-python-2-on-mac-12-3/</link><guid isPermaLink="false">Ghost__Post__6258204839840e1ac2874e74</guid><category><![CDATA[Tips]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 14 Apr 2022 13:34:57 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/6091f831ffb568e0450ce955625cd203/B7973617-B25E-4E6A-9C4B-DB17F090A267.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/6091f831ffb568e0450ce955625cd203/B7973617-B25E-4E6A-9C4B-DB17F090A267.png" alt="How to Install Python 2 on macOS 12.3+"/><p>As of <a href="https://developer.apple.com/documentation/macos-release-notes/macos-12_3-release-notes#Python">macOS 12.3+</a>, Python 2 which was installed by default at <code class="language-text">/usr/bin/python</code> have been removed. This can lead to a lot of issues for developers that need to use Python 2 or that use other tools that depend on it.</p><h2 id="install-python-2">Install Python 2</h2><p>To install Python2 again, simply <a href="https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg">download the macOS universal installer from Python's website</a></p><p>After downloading the installer run it to install Python 2. This will automatically install Python in <code class="language-text">/usr/local/python</code> as well.</p><h2 id="test-it-out">Test it Out</h2><p>You can run Python 2 in your terminal now and other tools using it will no longer have issues:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">python</code></pre></div>]]></content:encoded></item><item><title><![CDATA[Does Technical Writing Require Technical Knowledge?]]></title><description><![CDATA[In this article, I'll give you a bit of summary about what we do and whether or not you need technical knowledge for the job.]]></description><link>https://blog.shahednasser.com/does-technical-writing-require-technical-knowledge/</link><guid isPermaLink="false">Ghost__Post__6251920039840e1ac2874dff</guid><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 11 Apr 2022 09:10:52 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/2a412602419b450246a9d574f73d01c8/Does-Technical-Writing-Require-Technical-Knowledge-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/2a412602419b450246a9d574f73d01c8/Does-Technical-Writing-Require-Technical-Knowledge-2.jpg" alt="Does Technical Writing Require Technical Knowledge?"/><p>Something I constantly see on Twitter is threads that list people's jobs in the technical fields that don't require a lot or any technical knowledge. Some of those threads include Technical Writing. </p><p>I'm a technical writer, I had been a freelance technical writer for almost a year and now I'm working full-time. In this article, I'll give you a bit of summary about what we do and whether or not you need technical knowledge for the job.</p><h2 id="documentation">Documentation</h2><p>Documentation generally is a huge part of your work as a technical writer. Most, if not all, companies hire a technical writer to write documentation about their software.</p><p>The reason I'm saying most and not all is that some companies hire technical writers exclusively for blog content, especially if that company works as a digital marketing or content provider for other software companies. I'll get to the blog posts later on.</p><p>There are two types of documentation: user documentation and developer documentation. Some companies need you to write both. Some companies need you to write one or the other, depending on the type of solution they provide.</p><h3 id="developer-documentation">Developer Documentation</h3><p>Writing documentation for developers requires you to sift through code written by other people to understand many things such as how something is done, how something is actually implemented, or why something is done a certain way.</p><p>This deep dive into the code requires you to have some knowledge of programming, especially in the language you're working with. The level of that knowledge depends on the type of software you're working on.</p><p>You can also rely on the technical team by asking them questions if anything is unclear or you need to confirm some details.</p><p>Working with documentation also requires you to actually build with the software at times to be able to explain the process, including code snippets, and test things out yourself.</p><h3 id="user-documentation">User Documentation</h3><p>Writing documentation might require less technical knowledge than that required for writing for developers. When you write documentation for users, it's often done in a way to simplify how to use a process. Users don't necessarily care about the code or how it's implemented.</p><h2 id="articles-and-blogs">Articles and Blogs</h2><p>Another aspect of being a technical writer is writing articles. There are many types of articles you can work on, and again it depends on what type of company you're in.</p><p>One type is tutorial articles. You have to guide developers on how they can do something using the software. Those obviously require technical knowledge as you'll be building the solution yourself while writing about it.</p><p>Another type is general articles that might explain topics and concepts related to the product your company provides or programming in general. Although those might not have code snippets in them or might not require you to build anything throughout the article, they require a deep understanding of the topic at hand.</p><p>As it is a technical topic, you should have some technical knowledge to be able to write about it correctly.</p><h2 id="conclusion">Conclusion</h2><p>Technical Writing jobs can vary from one company to another, but generally speaking, the technical part is a prominent part of it. If you're interested in technical writing, make sure you also develop your technical knowledge and skills as well.</p>]]></content:encoded></item><item><title><![CDATA[Optional Chaining in JavaScript]]></title><description><![CDATA[In this article, you’ll learn how and when to use Optional Chaining.]]></description><link>https://syntackle.live/blog/optional-chaining-in-javascript-D6SuXGtu0-K5hhtZUqqc/</link><guid isPermaLink="false">Ghost__Post__6248411d39840e1ac2874da6</guid><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Murtuzaali Surti]]></dc:creator><pubDate>Mon, 04 Apr 2022 09:03:21 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/d9ed2e7558824339cb9d44e26a029146/Optional-Chaining-in-JavaScript.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/d9ed2e7558824339cb9d44e26a029146/Optional-Chaining-in-JavaScript.jpg" alt="Optional Chaining in JavaScript"/><p>Optional Chaining in JavaScript is used to return <code class="language-text">undefined</code> for accessing an object property that doesn't exist and whose parent property is <em><strong>nullish (null or undefined).</strong></em></p><p>If you are unaware that property exists or not and you want to avoid the error that's being thrown, you may want to use optional chaining to get around with it.</p><p>In this article, you’ll learn how and when to use Optional Chaining. You’ll also learn when not to use Optional Chaining in JavaScript.</p><h2 id="how-it-works">How it Works</h2><p>First, let's explore what can go wrong when accessing a property in a nested object.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">let</span> person <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">"Murtuza"</span><span class="token punctuation">,</span> <span class="token function-variable function">work</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">"Software Developer"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">socials</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">github</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">username</span><span class="token operator">:</span> <span class="token string">"murtuzaalisurti"</span><span class="token punctuation">,</span> <span class="token literal-property property">link</span><span class="token operator">:</span> <span class="token string">"https://github.com/murtuzaalisurti"</span><span class="token punctuation">,</span> <span class="token literal-property property">proUser</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">is</span><span class="token operator">:</span> <span class="token string">'no'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">linkedin</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">username</span><span class="token operator">:</span> <span class="token string">"murtuzaali-surti"</span><span class="token punctuation">,</span> <span class="token literal-property property">link</span><span class="token operator">:</span> <span class="token string">"https://linkedin.com/in/murtuzaali-surti"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">twitter</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">username</span><span class="token operator">:</span> <span class="token string">"murtuza_surti"</span><span class="token punctuation">,</span> <span class="token literal-property property">link</span><span class="token operator">:</span> <span class="token string">"https://twitter.com/murtuza_surti"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>In the above object, let's try to access the property link nested within the property website. Can we?</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>person<span class="token punctuation">.</span>website<span class="token punctuation">.</span>link<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//an error will be thrown</span></code></pre></div><p>We get an error,</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">Cannot read property <span class="token string">'link'</span> <span class="token keyword">of</span> <span class="token keyword">undefined</span></code></pre></div><p>The property website doesn't exist in the object!</p><p>But, let's add the property <code class="language-text">website</code> to the root object and set the value of it as <code class="language-text">null</code>.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token literal-property property">website</span><span class="token operator">:</span> <span class="token keyword">null</span></code></pre></div><p>Let's check if this works,</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>person<span class="token punctuation">.</span>website<span class="token punctuation">.</span>link<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//an error will be thrown</span></code></pre></div><p>We get a similar error,</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">Cannot read property <span class="token string">'link'</span> <span class="token keyword">of</span> <span class="token keyword">null</span></code></pre></div><p>As mentioned in the above definition, we can use optional chaining to handle these types of errors! Here's how we can do that.</p><h2 id="syntax">Syntax</h2><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token comment">// website: property to validate</span> <span class="token comment">// link: property to access</span> website<span class="token operator">?.</span>link</code></pre></div><p>The operator ?. will check if the property on its left-hand side is null or undefined and if that's the case, then it will simply return undefined without throwing any errors. In other words, this is also known as short-circuiting. Otherwise, it will return the value of the property on its right-hand side.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/04/rUOx6qB.gif" class="kg-image" alt="Optional Chaining in JavaScript" loading="lazy" width="1141" height="139"/></figure><p>Not just that, you can also invoke a function if it exists using optional chaining.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">person<span class="token punctuation">.</span>work<span class="token operator">?.</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span></code></pre></div><p>Also, you can access properties using [] brackets.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">person<span class="token punctuation">.</span>socials<span class="token punctuation">.</span>github<span class="token operator">?.</span><span class="token punctuation">[</span><span class="token string">"username"</span><span class="token punctuation">]</span></code></pre></div><h2 id="what-you-can%E2%80%99t-do">What You Can’t Do</h2><ul><li>You cannot apply optional chaining to the objects that are not declared yet. For example:</li></ul><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">object<span class="token operator">?.</span>prop <span class="token comment">// object is not defined</span></code></pre></div><p>We haven't declared <code class="language-text">object</code>, thus it will throw an error.</p><ul><li>You cannot assign a value to this expression. In other words, the optional chaining expression can't be on the left-hand side.</li></ul><p>The below code is not valid.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">person<span class="token punctuation">.</span>socials<span class="token punctuation">.</span>github<span class="token operator">?.</span><span class="token punctuation">[</span><span class="token string">"username"</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">"name"</span> <span class="token comment">// not valid</span></code></pre></div><h2 id="when-to-use-optional-chaining">When to Use Optional Chaining?</h2><p>It's important to note that optional chaining should not be used when it's not necessary to do so. Only use optional chaining when you know that the property that you want to access is optional and not mandatory.</p><p>For example, in our object <code class="language-text">person</code>, we can keep the social media platforms optional, so we are not sure if a user has a social media account or not on a particular platform. For that, we can use optional chaining to check if a user has a social media account on a particular platform and if it exists, get the username.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">person<span class="token punctuation">.</span>socials<span class="token punctuation">.</span>github<span class="token operator">?.</span><span class="token punctuation">[</span><span class="token string">"username"</span><span class="token punctuation">]</span></code></pre></div><p>But, if we place the optional chaining operator at the root object, then it doesn't make any sense because the root object i.e. person must exist and if it doesn't exist, we should get an error!</p><h2 id="conclusion">Conclusion</h2><p>In this article, you learned what Optional Chaining in JavaScript is, how it works when to use it, and when not to use it.</p><p>To learn more about how Optional Chaining works, make sure to check out the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining#specifications">MDN documentation</a> on it for more details.</p>]]></content:encoded></item><item><title><![CDATA[How I Monetize My Blog]]></title><description><![CDATA[I'm listing in this article a few ways I've made profit from my blog.]]></description><link>https://blog.shahednasser.com/how-i-monetize-my-blog/</link><guid isPermaLink="false">Ghost__Post__623f0d0d1594e705e60e1956</guid><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 28 Mar 2022 10:19:32 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/af17e22a50eb7f0cf09972cd860e08c4/How-to-Create-and-Validate-Forms-in-React-using-Formik-and-Yup-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/af17e22a50eb7f0cf09972cd860e08c4/How-to-Create-and-Validate-Forms-in-React-using-Formik-and-Yup-2.jpg" alt="How I Monetize My Blog"/><p>If you search Google for ways to earn money online, one of the most popular methods is starting a blog. It's stated as one of the slow yet effective ways to earn money online.</p><p>When I created my blog, my goal wasn't to monetize it. I just loved writing and wanted to do it on my own terms. Also, as a technical writer, I wanted to learn more and I think writing is one of the best ways.</p><p>However, I have been able to generate some profit through my blog. For that reason, I'm listing in this article a few ways I've made profit from my blog.</p><h2 id="costs-of-creating-a-blog">Costs of Creating a Blog</h2><p>Before you start talking about earning if you're creating your own blog you should think of the spending.</p><p>Generally speaking, when you create a blog you need to think about the costs of hosting and domain name. If you're not tech-savvy, then you might also need a developer to set it up and maintain it, but I won't get into the details of that.</p><p>There's a way to obtain both of those things for free, actually. I've listed some resources before in <a href="https://blog.shahednasser.com/the-things-you-can-do-for-free-the-ultimate-guide">my ultimate guide of things you can do for free</a>.</p><p>In my case, I've already purchased a personal domain, so I just used a subdomain of it to use for my blog.</p><p>As for the hosting, it depends on the type of blog you're running. In my case, my blog uses Ghost CMS as a headless backend and I connect it to a frontend built on Gatsby. This gives me more flexibility in the type of hosting.</p><p>I can host my Gatsby blog on <a href="https://www.netlify.com">Netlify</a> for free due to their generous free plan. As for the backend, I started off with free hosting on <a href="https://www.heroku.com">Heroku</a>. It was slow and limited, but as it was only for me to use to upload blog posts and didn't affect visitors' user experience, I had no issue with it.</p><p>Once I started earning some profit from my blog I switched to hosting my backend on <a href="https://www.digitalocean.com">DigitalOcean</a>. Again, as I am the only one using the backend, I opted for one of the cheaper plans.</p><h3 id="summary">Summary</h3><p>If you're considering hosting your own blog my tip for you is:</p><ol><li>If you need to get a domain name for free you can either use an existing domain and add a subdomain to it, use <a href="https://blog.shahednasser.com/the-things-you-can-do-for-free-the-ultimate-guide/#domain-name">free domain name providers</a>, or use subdomains provided by some hosting websites like Netlify.</li><li>Consider going for the headless CMS approach to have more flexibility for your hosting.</li></ol><p>Alternatively, you can use websites like <a href="https://blog.shahednasser.com/dev-vs-hashnode-vs-medium-which-platform-should-you-use-for-your-blog">Medium, Dev.to, or Hashnode</a> to create your own custom blog.</p><h2 id="carbon-ads">Carbon Ads</h2><p>One of the most common ways to make a profit off your blog is using ads, so I won't make this one long.</p><p>So many blogs go for Google ads. However, in my case, I was able to get <a href="https://www.carbonads.net">Carbon ads</a> instead. The reason I prefer Carbon ads is that the ads aren't annoying and are all engineering-related. So, the ads are relevant to my blog visitors.</p><h2 id="guest-posts">Guest Posts</h2><p>A lot of marketing companies write posts for their clients and look for blogs to post them. Usually, the posts are general posts that include a do-follow link to their client. When they post it on your blog, they pay you for the posting fees.</p><p>I started working with a bunch of marketing companies and individuals for that. However, it's important for me to ensure the quality of the content being posted on my website and the quality of links, as well.</p><p>If you have subscribers or followers, you should be careful with what kind of content you're sharing. Making a profit is not worth spamming them with content that's not relevant for them or educational. </p><p>So, I always do a review of the posts to be posted on my blog. I make sure its content is true, informative, and if it links to a client then it's not a scam.</p><p>If you're interested in doing this, you can have a <a href="https://blog.shahednasser.com/business/">Collaborate or Business page</a> on your blog detailing how this process works. You can also try contacting digital marketing agencies to offer your services, however, I personally haven't tried that.</p><h2 id="article-reviews">Article Reviews</h2><p>On my blog, I have a section called <a href="https://blog.shahednasser.com/tag/reviews/">Reviews</a>. It's all the articles I've written for clients who have asked me to review their products or services. You either get paid or get something related to the product like a free subscription forever.</p><p>Article reviews are not easy to find, because you're usually contacted by the company to write the review for them. However, I recommend that if you get an opportunity to write a review for a product in the beginning and it's not paid, take it. You can use it to showcase your work for future work with other companies.</p><p>Again, quality is important for your blog. So, make sure when you take on collaboration with companies, make sure it's something you believe in and something that is relevant for your blog's content.</p><h2 id="do-follow-links">Do-Follow Links</h2><p>Some companies don't want you to write a full article for them. They're just interested in you adding a link to their website on your website. They either pay you for it, add a do-follow link for your website on theirs, or share your website through their social media platforms.</p><p>If you do this one, you have to be careful with the quality of the websites you're linking to, as it can bring down your domain name rating if you link to websites with low-quality content. </p><h2 id="writing-for-other-websites">Writing for Other Websites</h2><p>Although this is not a profit directly coming from your own blog, it's related to it. Building a blog can be like building a portfolio for writers. You give other companies or agencies a taste of what you can do.</p><p>I was able to write on a lot of websites like SitePoint and ButterCMS because of all the writing I've done on my blog. It builds your experience and helps you a lot when applying to write for other agencies or websites. </p><h2 id="conclusion">Conclusion</h2><p>It's important to note that monetizing your blog can be a slow process. You need to make sure that you have quality content and you're consistent with your posting. That helps you gain regular readers and subscribers and will increase your ranking in search engines.</p><p>As your blog grows in quality, more opportunities to monetize it will come your way. Focus on the quality and durability of it first.</p>]]></content:encoded></item><item><title><![CDATA[How to Create and Validate Forms in React using Formik and Yup]]></title><description><![CDATA[In this tutorial, you'll learn how creating and validating forms can be simpler in React using Formik and Yup.]]></description><link>https://blog.shahednasser.com/how-to-create-and-validate-forms-in-react-using-formik-and-yup/</link><guid isPermaLink="false">Ghost__Post__6235d3ec1594e705e60e186f</guid><category><![CDATA[React]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 21 Mar 2022 10:55:46 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/91089d8a50da0ecc97647ef3cac82ba2/How-to-Create-and-Validate-Forms-in-React-using-Formik-and-Yup.webp" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/91089d8a50da0ecc97647ef3cac82ba2/How-to-Create-and-Validate-Forms-in-React-using-Formik-and-Yup.webp" alt="How to Create and Validate Forms in React using Formik and Yup"/><p>Perhaps one of the most annoying tasks in React is creating forms and validating them, especially if you're doing it without using any libraries. You'll have to manage the states, values, and validation of all inputs.</p><p><a href="https://formik.org">Formik</a> is a React and React Native library that helps you create forms in React "without the tears". You can pair Formik with validation libraries like <a href="https://github.com/jquense/yup">Yup</a> to make the process even simpler.</p><p>In this tutorial, you'll learn how creating and validating forms can be simpler in React using Formik and Yup. You'll create a simple form with different types of fields and see the different ways you can validate that form.</p><p>You can find the code for this tutorial in <a href="https://github.com/shahednasser/react-forms-tutorial">this GitHub repository</a>.</p><h2 id="project-setup">Project Setup</h2><p>In this section, you'll set up your website using <a href="https://create-react-app.dev">Create React App</a> (CRA) and install some dependencies for the sake of the tutorial. If you already have a website set up you can skip this part.</p><p>In your terminal, run the following command to create a new React website with CRA:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-react-app react-forms</code></pre></div><p>I'm calling the website <code class="language-text">react-forms</code> but you can change it to whatever you want.</p><p>Once the installation is done, change to the newly created directory:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> react-forms</code></pre></div><p>Then, install <a href="https://tailwindcss.com">Tailwind CSS</a> to add some styling to your website:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> -D tailwindcss postcss autoprefixer</code></pre></div><p>To set up Tailwind CSS create the file <code class="language-text">tailwind.config.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">module.exports <span class="token operator">=</span> <span class="token punctuation">{</span> content: <span class="token punctuation">[</span> <span class="token string">"./src/**/*.{js,jsx,ts,tsx}"</span>, <span class="token punctuation">]</span>, theme: <span class="token punctuation">{</span> extend: <span class="token punctuation">{</span><span class="token punctuation">}</span>, <span class="token punctuation">}</span>, plugins: <span class="token punctuation">[</span><span class="token punctuation">]</span>, <span class="token punctuation">}</span></code></pre></div><p>And replace the content of <code class="language-text">src/index.css</code> with the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">@tailwind base<span class="token punctuation">;</span> @tailwind components<span class="token punctuation">;</span> @tailwind utilities<span class="token punctuation">;</span></code></pre></div><h2 id="create-the-form-with-formik">Create the Form with Formik</h2><p>You'll now use Formik to create a form. First, install Formik:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i formik</code></pre></div><p>Replace the content of <code class="language-text">src/App.js</code> with the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useFormik <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'formik'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> professions <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'Developer'</span><span class="token punctuation">,</span> <span class="token string">'Designer'</span><span class="token punctuation">,</span> <span class="token string">'Other'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">//TODO create formik instance</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"bg-blue-300 min-w-screen min-h-screen overflow-x-hidden"</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span></code></pre></div><p>All you did here is create the component App which does nothing special at the moment.</p><p>Notice how you import the <code class="language-text">useFormik</code> hook at the beginning of the file. You'll use this hook to create a Formik instance with all the states and helpers you'll need.</p><p>The <code class="language-text">useFormik</code> hook accepts as a parameter an object of <a href="https://formik.org/docs/api/formik#props-1">configurations</a>. These configurations can be used to modify and shape your form as you need.</p><p>In this tutorial, you'll use the pass the following properties in the object:</p><ol><li><code class="language-text">initialValues</code>: includes the form fields and their initial values.</li><li><code class="language-text">validationSchema</code>: A Yup schema to validate the fields. You'll use this in the next section.</li><li><code class="language-text">onSubmit</code>: a function to execute when the form is submitted.</li></ol><p>Replace the <code class="language-text">TODO</code> in the <code class="language-text">App</code> component with the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> formik <span class="token operator">=</span> <span class="token function">useFormik</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">initialValues</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">email</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">profession</span><span class="token operator">:</span> professions<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token function-variable function">onSubmit</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">values</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">You are registered! Name: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>values<span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">. Email: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>values<span class="token punctuation">.</span>email<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">. Profession: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>values<span class="token punctuation">.</span>profession<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">. Age: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>values<span class="token punctuation">.</span>age<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>As you can see, you set the value of the property <code class="language-text">initialValues</code> to an object. This object's keys are the names of the fields in the form. Their values are the initial value.</p><p>In the <code class="language-text">onSubmit</code> function, you receive the <code class="language-text">values</code> object as a parameter. Here you can access the values and use them to save them in the database or send them to a server. For the sake of this tutorial, you just print them out in an alert.</p><p>Note that the <code class="language-text">onSubmit</code> function is only executed once the form is validated. So, you don't need to perform any validation inside this function.</p><p>Now, you can use the <code class="language-text">formik</code> variable to create a form, link its fields to the fields you defined in <code class="language-text">useFormik</code>, link the validation, and link the submit handler.</p><p><code class="language-text">formik</code> includes the following properties among <a href="https://formik.org/docs/api/formik#props-1">others</a>:</p><ol><li><code class="language-text">handleSubmit</code>: the submit function that should be called when the form is submitted. This is usually assigned to the <code class="language-text">onSubmit</code> event handler of <code class="language-text">form</code> elements.</li><li><code class="language-text">errors</code>: An object that has the field names as properties and the value of each is the error message resulted from validating that field if there are any errors.</li><li><code class="language-text">touched</code>: An object that has the field names as properties and the value is a boolean indicating whether the user has interacted with the field or not.</li><li><code class="language-text">values</code>: An object that has the field names as properties and the value of each is the current value of that field. It's usually used to set the <code class="language-text">value</code> property of input elements.</li><li><code class="language-text">handleChange</code>: A function that should be used as the handler of the change event of input elements. It's passed as the value of the <code class="language-text">onChange</code> prop of elements.</li><li><code class="language-text">handleBlur</code>: A function that should be used as the handler of the blur event of input elements. It's passed as the value of the <code class="language-text">onBlur</code> prop of elements.</li></ol><p>Replace the return statement in <code class="language-text">App</code> with the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"bg-blue-300 min-w-screen min-h-screen overflow-x-hidden"</span><span class="token operator">></span> <span class="token operator"><</span>form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>handleSubmit<span class="token punctuation">}</span> className<span class="token operator">=</span><span class="token string">"max-w-lg mx-auto bg-white rounded shadow-lg mt-7 p-3"</span><span class="token operator">></span> <span class="token operator"><</span>h1 className<span class="token operator">=</span><span class="token string">'text-3xl mb-3 text-center'</span><span class="token operator">></span>Register<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">'mb-4'</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string">"name"</span><span class="token operator">></span>Full Name<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"text"</span> name<span class="token operator">=</span><span class="token string">"name"</span> id<span class="token operator">=</span><span class="token string">"name"</span> className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">block w-full rounded border py-1 px-2 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>formik<span class="token punctuation">.</span>touched<span class="token punctuation">.</span>name <span class="token operator">&&</span> formik<span class="token punctuation">.</span>errors<span class="token punctuation">.</span>name <span class="token operator">?</span> <span class="token string">'border-red-400'</span> <span class="token operator">:</span> <span class="token string">'border-gray-300'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>handleChange<span class="token punctuation">}</span> onBlur<span class="token operator">=</span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>handleBlur<span class="token punctuation">}</span> value<span class="token operator">=</span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>values<span class="token punctuation">.</span>name<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">{</span>formik<span class="token punctuation">.</span>touched<span class="token punctuation">.</span>name <span class="token operator">&&</span> formik<span class="token punctuation">.</span>errors<span class="token punctuation">.</span>name <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token operator"><</span>span className<span class="token operator">=</span><span class="token string">'text-red-400'</span><span class="token operator">></span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>errors<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">'mb-4'</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string">"email"</span><span class="token operator">></span>Email<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"email"</span> name<span class="token operator">=</span><span class="token string">"email"</span> id<span class="token operator">=</span><span class="token string">"email"</span> className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">block w-full rounded border py-1 px-2 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>formik<span class="token punctuation">.</span>touched<span class="token punctuation">.</span>email <span class="token operator">&&</span> formik<span class="token punctuation">.</span>errors<span class="token punctuation">.</span>email <span class="token operator">?</span> <span class="token string">'border-red-400'</span> <span class="token operator">:</span> <span class="token string">'border-gray-300'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>handleChange<span class="token punctuation">}</span> onBlur<span class="token operator">=</span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>handleBlur<span class="token punctuation">}</span> value<span class="token operator">=</span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>values<span class="token punctuation">.</span>email<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">{</span>formik<span class="token punctuation">.</span>touched<span class="token punctuation">.</span>email <span class="token operator">&&</span> formik<span class="token punctuation">.</span>errors<span class="token punctuation">.</span>email <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token operator"><</span>span className<span class="token operator">=</span><span class="token string">'text-red-400'</span><span class="token operator">></span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>errors<span class="token punctuation">.</span>email<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">'mb-4'</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string">"profession"</span><span class="token operator">></span>Profession<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>select name<span class="token operator">=</span><span class="token string">"profession"</span> id<span class="token operator">=</span><span class="token string">"profession"</span> className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">block w-full rounded border py-1 px-2 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>formik<span class="token punctuation">.</span>touched<span class="token punctuation">.</span>profession <span class="token operator">&&</span> formik<span class="token punctuation">.</span>errors<span class="token punctuation">.</span>profession <span class="token operator">?</span> <span class="token string">'border-red-400'</span> <span class="token operator">:</span> <span class="token string">'border-gray-300'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>handleChange<span class="token punctuation">}</span> onBlur<span class="token operator">=</span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>handleBlur<span class="token punctuation">}</span> value<span class="token operator">=</span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>values<span class="token punctuation">.</span>profession<span class="token punctuation">}</span> <span class="token operator">></span> <span class="token punctuation">{</span>professions<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">profession<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token punctuation">{</span>profession<span class="token punctuation">}</span> key<span class="token operator">=</span><span class="token punctuation">{</span>index<span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{</span>profession<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>select<span class="token operator">></span> <span class="token punctuation">{</span>formik<span class="token punctuation">.</span>touched<span class="token punctuation">.</span>profession <span class="token operator">&&</span> formik<span class="token punctuation">.</span>errors<span class="token punctuation">.</span>profession <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token operator"><</span>span className<span class="token operator">=</span><span class="token string">'text-red-400'</span><span class="token operator">></span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>errors<span class="token punctuation">.</span>profession<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">'mb-4'</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string">"age"</span><span class="token operator">></span>Age<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"number"</span> name<span class="token operator">=</span><span class="token string">"age"</span> id<span class="token operator">=</span><span class="token string">"age"</span> className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">block w-full rounded border py-1 px-2 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>formik<span class="token punctuation">.</span>touched<span class="token punctuation">.</span>age <span class="token operator">&&</span> formik<span class="token punctuation">.</span>errors<span class="token punctuation">.</span>age <span class="token operator">?</span> <span class="token string">'border-red-400'</span> <span class="token operator">:</span> <span class="token string">'border-gray-300'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>handleChange<span class="token punctuation">}</span> onBlur<span class="token operator">=</span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>handleBlur<span class="token punctuation">}</span> value<span class="token operator">=</span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>values<span class="token punctuation">.</span>age<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">{</span>formik<span class="token punctuation">.</span>touched<span class="token punctuation">.</span>age <span class="token operator">&&</span> formik<span class="token punctuation">.</span>errors<span class="token punctuation">.</span>age <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token operator"><</span>span className<span class="token operator">=</span><span class="token string">'text-red-400'</span><span class="token operator">></span><span class="token punctuation">{</span>formik<span class="token punctuation">.</span>errors<span class="token punctuation">.</span>age<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">'text-center'</span><span class="token operator">></span> <span class="token operator"><</span>button className<span class="token operator">=</span><span class="token string">'bg-blue-500 rounded p-3 text-white'</span> type<span class="token operator">=</span><span class="token string">'submit'</span><span class="token operator">></span>Submit<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Notice how you used all the properties in the <code class="language-text">formik</code> variable mentioned earlier.</p><h3 id="test-it-out">Test it Out</h3><p>The form is now created and ready to be used, even if there's no validation yet.</p><p>To test it out, run the server using the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>You can then open the website at <code class="language-text">localhost:3000</code> (default port). If you open the website, you'll see the form with 4 fields.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-03-19-at-2.49.28-PM-1.png" class="kg-image" alt="How to Create and Validate Forms in React using Formik and Yup" loading="lazy" width="1084" height="900"/></figure><p>You can try and fill out the form. As currently there's no validation, you can fill out (or not) values as you want and click Submit. An alert will show with the values you entered.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-03-19-at-2.50.35-PM-1.png" class="kg-image" alt="How to Create and Validate Forms in React using Formik and Yup" loading="lazy" width="1010" height="410"/></figure><h2 id="add-validation-with-yup">Add Validation with Yup</h2><p>In this section, you'll add validation to the form using Yup.</p><p>First, you need to install Yup. Run the following in your terminal:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i yup</code></pre></div><p>Yup has a lot of <a href="https://github.com/jquense/yup#table-of-contents">methods and validation rules</a> you can use. The way it works with Formik is you need to create a validation schema and pass it to <code class="language-text">useFormik</code> as a value to the property <code class="language-text">validationSchema</code>.</p><p>Yup validation schemas are created using <code class="language-text">Yup.object</code> method which takes as a parameter an object. This object has the field names as properties and their values are validation rules from the Yup library.</p><p>Import Yup at the beginning of <code class="language-text">src/App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> Yup <span class="token keyword">from</span> <span class="token string">'yup'</span><span class="token punctuation">;</span></code></pre></div><p>Then, add the property <code class="language-text">validationSchema</code> to the object passed to <code class="language-text">useFormik</code> with the following value:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> formik <span class="token operator">=</span> <span class="token function">useFormik</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token operator">...</span><span class="token punctuation">,</span> <span class="token literal-property property">validationSchema</span><span class="token operator">:</span> Yup<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> Yup<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">label</span><span class="token punctuation">(</span><span class="token string">'Full Name'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">required</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">email</span><span class="token operator">:</span> Yup<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">required</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">profession</span><span class="token operator">:</span> Yup<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">oneOf</span><span class="token punctuation">(</span>professions<span class="token punctuation">,</span> <span class="token string">'The profession you chose does not exist'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> Yup<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">,</span> <span class="token string">'You need to be older than 15 to register'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">required</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>You add the following validation rules:</p><ol><li><code class="language-text">name</code>: Should be a string and is required. You also use the <code class="language-text">label</code> method to ensure that when the error message is shown it refers to the field as "Full Name". By default, the fields are referred to by the field name, which in this case is <code class="language-text">name</code>.</li><li><code class="language-text">email</code>: Should be a string, an email, and required.</li><li><code class="language-text">profession</code>: Should be a string and one of the values in the <code class="language-text">professions</code> array. You also pass a message as a second parameter to <code class="language-text">oneOf</code> which will be the message that shows in case there's an error. It's also required.</li><li><code class="language-text">age</code>: Should be a number and at least 15. If the age is less than 15, the message "You need to be older than 15 to register" will show. It's also required.</li></ol><h3 id="test-it-out-1">Test it Out</h3><p>Let's test it out. Run the server again if it's not running and open the website. If you enter values now that don't comply with the rules you set in the validation schema, an error will show in red and you won't be able to submit the form before resolving the errors.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-03-19-at-2.55.58-PM-1.png" class="kg-image" alt="How to Create and Validate Forms in React using Formik and Yup" loading="lazy" width="1102" height="938"/></figure><p>If you all values are valid, then the form will be submitted and an alert will show.</p><h3 id="custom-validation-rules">Custom Validation Rules</h3><p>Although Yup has helpful validation rules that you can use with most common cases, a lot of times you might need a custom validation rule. You can use the <a href="https://github.com/jquense/yup#schematestname-string-message-string--function--any-test-function-schema">test</a> function to add a custom rule.</p><p>In this section, you'll add a rule to make sure that the <code class="language-text">name</code> field has both first and last name.</p><p>Change the <code class="language-text">name</code> property inside the <code class="language-text">validationSchema</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> formik <span class="token operator">=</span> <span class="token function">useFormik</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token operator">...</span><span class="token punctuation">,</span> <span class="token literal-property property">validationSchema</span><span class="token operator">:</span> Yup<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> Yup<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">label</span><span class="token punctuation">(</span><span class="token string">'Full Name'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">required</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'is-full-name'</span><span class="token punctuation">,</span> <span class="token string">'Please enter both your first and last name'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> nameArr <span class="token operator">=</span> value<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">" "</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> nameArr<span class="token punctuation">.</span>length <span class="token operator">>=</span> <span class="token number">2</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token operator">...</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>The first parameter is the name of the custom rule. The second parameter is the message to show in case the field is invalid. </p><p>The third parameter is the function that determines whether the field is valid or not. It should return a boolean value. If the value is true, then the field is valid. Otherwise, it's invalid.</p><p>You validate the name field to contain both first and last names by just splitting it on the space delimiter which will return an array. You then check the array length. If it's at least 2, then the field is valid. Otherwise it's invalid.</p><h3 id="test-it-out-2">Test it Out</h3><p>Run the server again now and go to the website. If you enter one word in the Full Name field you'll see an error.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/us9mldxrs5dvf174r4w9.png.jpeg" class="kg-image" alt="How to Create and Validate Forms in React using Formik and Yup" loading="lazy" width="880" height="192"/></figure><p>You'll need to enter at least two words for the field to be valid.</p><h2 id="conclusion">Conclusion</h2><p>In this tutorial you learned how to use Formik and Yup in React. You can use these two libraries to create forms, validate them, and handle their submission. Using these two libraries makes creating forms in React easier and less stressful.</p>]]></content:encoded></item><item><title><![CDATA[Why I Transitioned From a Full-Stack Developer to a Technical Writer]]></title><description><![CDATA[In this article, I share with you how I first started technical writing, and why am I transitioning into full-time technical writing.]]></description><link>https://blog.shahednasser.com/why-i-transitioned-from-a-full-stack-developer-to-a-technical-writer/</link><guid isPermaLink="false">Ghost__Post__6228bd111594e705e60e17b9</guid><category><![CDATA[My Experience]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 15 Mar 2022 07:45:23 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/a480d0fc68fa0b126f4d03c77dc61317/Why-I-Transitioned-From-a-Full-Stack-Developer-to-a-Technical-Writer.webp" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/a480d0fc68fa0b126f4d03c77dc61317/Why-I-Transitioned-From-a-Full-Stack-Developer-to-a-Technical-Writer.webp" alt="Why I Transitioned From a Full-Stack Developer to a Technical Writer"/><p>For the past 5 years, I've been working as a full-stack developer, both full-time and freelance. I learned a lot through it and have become better with time.</p><p>A year ago I started technical writing. I wrote articles, tutorials, and documentation for my own blog as well as other websites, agencies, and clients. It became a hobby of mine that I really enjoyed.</p><p>Today, I start my new job as a Technical Writer at <a href="https://www.medusajs.com">Medusa</a>. This decision wasn't an easy one and it took me a while to finally make the transition.</p><p>In this article, I share with you how I first started technical writing, and why am I transitioning into full-time technical writing.</p><h2 id="how-it-started">How it Started</h2><p>I've always loved writing in general. For a long time, I debated whether I should create a blog or not. Although I have my fair share of experience as a developer, I still considered myself an average developer. So, I didn't think anyone would be interested to read my content or that I had anything helpful to share.</p><p>I finally decided to create my own blog in December 2020. It wasn't because I suddenly gained the motivation or courage. It was mostly a "even if I fail and no one reads my content, what could go wrong?" kind of decision. I tried a different kind of content. Some got a lot of attention from other developers, others not so much. However, the best part about it all was receiving feedback, even from one person, saying that this article or tutorial helped them understand or learn something better.</p><p> Then, at the end of March 2021, I learned that you can actually get paid to write for other websites! It may seem like common knowledge to a lot of people, but to me it was news. I didn't know whether my content was good enough or not, but I decided to apply anyway. I applied to a lot of websites and agencies, and that's what really kickstarted my technical writing journey.</p><p>In the past year, I was able to write for a lot of websites and agencies like <a href="https://blog.shahednasser.com/8-technical-writing-tips-i-learned-from-writing-for-sitepoint-draft-dev-and-more">SitePoint, Draft.dev, LogRocket, and more</a>. I was also able to work with my own clients, which was how I started my journey with Medusa.</p><p>Even though I really loved technical writing, it took a lot of thinking and consideration to finally embark on this journey and become a full-time technical writer.</p><h2 id="why-i-made-the-transition">Why I Made the Transition</h2><h3 id="learn-more">Learn More</h3><p>As I mentioned earlier I learned a lot from being a developer. However, when you are a developer a lot of time, especially if you work for a company that creates websites for other companies rather than having its own product, you end up prioritizing delivering features rather than the quality of the code or architecture. It becomes a "let's just get this over with" sort of mentality. </p><p>When I started technical writing, however, I became more curious. I started thinking "ok, but how does this thing work?" I also began diving more deeply into topics rather than learning surface-level details. </p><p>Even if you're not interested in writing, I recommend that you take the time to write about things as you learn them. It'll help you truly understand what you're learning instead of just applying.</p><h3 id="help-beginners">Help Beginners</h3><p>My main focus when writing is making sure that my content is easily understandable by beginners. Whether it's beginners to programming in general or to a certain tool, framework, or programming language. </p><p>I like to simplify my content, whether in the words I use or the approach I take. The first tutorial or guide a beginner finds while learning something can be a make-it or break-it sort of thing. If it's too complicated or doesn't give the reader a real understanding of what they're doing, it's a waste of their time.</p><h3 id="closer-to-the-community">Closer to the Community</h3><p>I'm an introverted person. I've always struggled with communicating with people in general. This has also stopped me from becoming closer to the tech community in the past years. </p><p>Ever since I started sharing my content across platforms, it helped me meet new people, learn from people's feedback, and have more love and support for the community. And going back to the previous point, it made me want to make more (hopefully helpful) content for those in the community who do not necessarily have access to paid resources.</p><h3 id="build-the-foundation">Build the Foundation</h3><p>This is specific to my work at Medusa. As Medusa is a fairly new platform, we are still lacking in terms of technical content and documentation. We are going to be building the documentation from the ground up to ensure that it's easy to understand by anyone who wishes to use and learn about the platform.</p><p>As I believe that Medusa will become more and more successful in the upcoming years, I'm excited to be part of the team working on the foundation of the documentation of a platform that will hopefully grow with time.</p><p>Also, as an open-source platform that appreciates and works closely with its community, Medusa's values align well with why I love writing and want to keep doing it.</p><h2 id="conclusion">Conclusion</h2><p>This is a personal post that maybe not many will read or be interested in. But this is a very important one for me. After a long time of struggling to find my footing in my career, I've finally reached a point where I understand what I want and have the opportunity to get there.</p><p>If you're reading this and you're still confused about what direction you want to go in, give yourself some time and experiment with different projects. As cheesy as it sounds, with hard work and dedication you'll get there sooner or later.</p>]]></content:encoded></item><item><title><![CDATA[How to Create an NPX Tool]]></title><description><![CDATA[In this tutorial, you'll learn how you can create your own NPX tool and publish it.]]></description><link>https://blog.shahednasser.com/how-to-create-a-npx-tool/</link><guid isPermaLink="false">Ghost__Post__6220989c1594e705e60e16fa</guid><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 08 Mar 2022 07:58:36 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/a1554d17767a4863730250538dc40435/How-to-Create-an-NPX-Tool.webp" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/a1554d17767a4863730250538dc40435/How-to-Create-an-NPX-Tool.webp" alt="How to Create an NPX Tool"/><p><a href="https://www.npmjs.com">NPM</a> (stands for Node Package Manager) is widely used by web developers to install and manage a variety of JavaScript libraries. It's a necessity for more websites nowadays. It comes installed with Node.js by default.</p><p>However, you've probably seen a lot of libraries or frameworks instructing you to use NPX when installing their packages. <a href="https://reactjs.org/docs/create-a-new-react-app.html">React</a> even has a warning that clarifies for developers that using NPX is not a typo.</p><p>NPX is a package runner that allows you to run CLI tools or executables hosted on NPM without the need to install them with NPM first.</p><p>For example, previously you'd need to install <code class="language-text">create-react-app</code> globally on your system, then run <code class="language-text">create-react-app my-website</code>.</p><p>Ever since NPM v5.2, there's no need to install <code class="language-text">create-react-app</code> globally (and it's recommended that you don't). You can simply run <code class="language-text">npx create-react-app my-website</code> and the same script will run to create your React app.</p><p>In this tutorial, you'll learn how you can create your own NPX tool. The tool you'll create through this tutorial is pretty simple – it'll only multiply 2 or more numbers. You'll also learn how you can use your tool locally and how you can publish it on the NPM registry for others to use.</p><h2 id="prerequisites">Prerequisites </h2><p>This is pretty obvious, but you need <a href="https://nodejs.dev">Node.js</a> installed to go through this tutorial. Installing Node.js will install in turn NPM and NPX.</p><h2 id="project-setup">Project Setup</h2><p>Create a new directory that will hold your tool:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> multiply-tool</code></pre></div><p>Next, initialize your project with NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> init</code></pre></div><p>You'll be asked a few questions about the package such as package name and author name. After you fill them out, a <code class="language-text">package.json</code> file will be created in the current directory.</p><h2 id="create-the-bin-file">Create the Bin File</h2><p>When you create a CLI tool or an executable file, you need to create a file and include it in your package.json under the <code class="language-text">bin</code> field.</p><p>Create the directory <code class="language-text">bin</code> and inside that directory create the file <code class="language-text">index.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token hashbang comment">#! /usr/bin/env node</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Hello, World!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>All this file will do (for now) is print "Hello, World!" to your command line or terminal. However, the important thing to note here is the following line:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">#! /usr/bin/env node</code></pre></div><p>This line should be added to all files that will be executed through the command line. It's called a <a href="https://en.wikipedia.org/wiki/Shebang_(Unix)">Shebang</a>, and basically, it specifies what interpreter the file should be passed to for execution in Unix-like systems.</p><p>Next, in <code class="language-text">package.json</code> add the new field <code class="language-text">bin</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"bin"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"multiply"</span><span class="token operator">:</span> <span class="token string">"bin/index.js"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>This means that when the user runs <code class="language-text">npx <package_name></code> the script <code class="language-text">bin/index.js</code> will run.</p><h2 id="test-it-locally">Test it Locally</h2><p>To test it locally, first, install the package globally in your system:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i -g</code></pre></div><p>You should run this command inside the directory that holds your package.</p><p>Then, in your terminal, run the following command to run your NPX tool:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx multiply</code></pre></div><p>Here, <code class="language-text">multiply</code> is the name of the package. If you named your package something else be sure to put the name of the package.</p><p>When you run the command, you'll see "Hello, World!" printed in your terminal.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-03-03-at-12.16.27-PM.png.jpeg" class="kg-image" alt="How to Create an NPX Tool" loading="lazy" width="880" height="67"/></figure><h2 id="using-arguments">Using Arguments</h2><p>In this section, you'll implement the functionality of the <code class="language-text">multiply</code> package. This package should accept at least two arguments (if the arguments are less than 2, the user will get an error). Then, it will multiply all the arguments. If the result is <code class="language-text">NaN</code> it means that at least one argument is not a number and the user will see an error in that case as well.</p><p>Replace the content of <code class="language-text">bin/index.js</code> with the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token hashbang comment">#! /usr/bin/env node</span> <span class="token keyword">const</span> args <span class="token operator">=</span> process<span class="token punctuation">.</span>argv<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>args<span class="token punctuation">.</span>length <span class="token operator"><</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Please enter at least 2 numbers'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> process<span class="token punctuation">.</span><span class="token function">exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//an error occurred</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> total <span class="token operator">=</span> args<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">previous<span class="token punctuation">,</span> current</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">parseFloat</span><span class="token punctuation">(</span>current<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token function">parseFloat</span><span class="token punctuation">(</span>previous<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isNaN</span><span class="token punctuation">(</span>total<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'One or more arguments are not numbers'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> process<span class="token punctuation">.</span><span class="token function">exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//an error occurred</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>total<span class="token punctuation">)</span><span class="token punctuation">;</span> process<span class="token punctuation">.</span><span class="token function">exit</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//no errors occurred</span></code></pre></div><p>A few things to note:</p><ol><li><code class="language-text">process.argv</code> is used to retrieve the command line arguments. The first 2 arguments will be the interpreter running this script (which is Node in this case), and the second argument is the name of the package (which is <code class="language-text">multiply</code> in this case). Any other arguments passed will be available starting from index <code class="language-text">2</code>. So, to get the arguments passed by the user you need to slice the array <code class="language-text">process.argv</code> and get the elements starting from the index <code class="language-text">2</code>.</li><li>When an error occurs, you can use <code class="language-text">process.exit(1)</code> to indicate that. If <code class="language-text">process.exit</code> receives a value other than 0 it means that an error occurred in the CLI tool.</li><li>The <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce">reduce</a> array function is used to multiply all items in the array one by one.</li><li>If the final result of <code class="language-text">total</code> is <code class="language-text">NaN</code>, the user will get an error.</li><li>If everything is successful, the result will be printed out and the process will exit with <code class="language-text">0</code> indicating that the process ended successfully.</li></ol><p>Let's test it out. Run the command again in your terminal passing it 2 numbers:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx multiply <span class="token number">3</span> <span class="token number">15</span></code></pre></div><p>You will see the result of the multiplication in your terminal.</p><p>You can also try adding more than 2 numbers and you'll see the result. To see how the error messages work, try entering less than 2 numbers or entering strings instead of numbers.</p><h2 id="publishing-the-package">Publishing the Package</h2><p>Now that your tool is ready, you can publish it on NPM. This step requires an NPM account, so if you don't have one make sure to <a href="https://www.npmjs.com/signup">create one</a>.</p><p>Then, in your terminal, run the following command to log in using your NPM account:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> login</code></pre></div><p>You'll be prompted to enter your username and password. If all is correct, you'll be logged in and you can then publish your tool.</p><p>To publish your tool, simply run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> publish</code></pre></div><blockquote>Note: If you're using a GitHub repository for your project make sure to commit everything before running this command.</blockquote><p>This will publish your tool into the NPM registry. Please note that if another package is created with the same name you'll need to change the name of your package in <code class="language-text">package.json</code> then try publishing again.</p><h2 id="use-your-published-package">Use Your Published Package</h2><p>To use your published package, you can run the same command you used earlier when running your local command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx <span class="token operator"><</span>package_name<span class="token operator">></span></code></pre></div><p>Notice how you don't need to install your package globally in this case. You can just run it through NPX.</p><p>In my case, I had to rename my package to <code class="language-text">multiply-tool</code> since <code class="language-text">multiply</code> already existed in the NPM registry. Then, I ran the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx multiply-tool <span class="token number">3</span> <span class="token number">15</span></code></pre></div><p>And received the result of the multiplication:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-03-03-at-12.25.53-PM-1.png.jpeg" class="kg-image" alt="How to Create an NPX Tool" loading="lazy" width="880" height="81"/></figure><h2 id="update-your-package">Update Your Package</h2><p>To update your package, you can use the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> version <span class="token operator"><</span>type<span class="token operator">></span></code></pre></div><p>Where <code class="language-text"><type></code> determines how to increment the version. It can be one of the following values:</p><ol><li><code class="language-text">patch</code>: This will increment the last number in your version and it usually means a small change. For example, it would change the version from <code class="language-text">1.0.0</code> to <code class="language-text">1.0.1</code>.</li><li><code class="language-text">minor</code>: This will increment the second number in your version and it usually means a minor change that doesn't necessarily affect how the user uses this tool. For example, it would change the version from <code class="language-text">1.0.0</code> to <code class="language-text">1.1.0</code>.</li><li><code class="language-text">major</code>: This will increment the first number in your version it usually means that a big change happened that can affect how this tool is used. For example, it would change the version from <code class="language-text">1.0.0</code> to <code class="language-text">2.0.0</code>.</li></ol><p>After running the above command run the publish command again:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> publish</code></pre></div><p>And your tool will be updated.</p><h2 id="conclusion">Conclusion</h2><p>In this tutorial, you learned how to create a tool that can be run with NPX directly without the need to install it globally. You also learned how to publish the tool and update it.</p><p>This tool is a simple tool, however, for more complex tools you can use helper libraries like <a href="https://www.npmjs.com/package/commander">commander</a> and <a href="https://www.npmjs.com/package/chalk">chalk</a>. </p>]]></content:encoded></item><item><title><![CDATA[Learning Python: Week 1 - From Operators to Generators]]></title><description><![CDATA[Go with me on the journey of learning Python.]]></description><link>https://blog.shahednasser.com/learning-python-week-1-from-operators-to-generators/</link><guid isPermaLink="false">Ghost__Post__6217c7d0eb81df0613580407</guid><category><![CDATA[Python]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 01 Mar 2022 10:13:17 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/6206d8c73a320c0de1fe17d8e8f0befb/Learning-Python-Week-1---From-Operators-to-Generators.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/6206d8c73a320c0de1fe17d8e8f0befb/Learning-Python-Week-1---From-Operators-to-Generators.jpg" alt="Learning Python: Week 1 - From Operators to Generators"/><p>Recently, I decided that I will start learning Python. I'm already familiar with the language, what can be done with it, and some of the syntaxes as well. However, I never took the time to properly learn it and create projects with it.</p><p>But why am I writing about it? Ever since I created my blog and started writing I've noticed how much writing has helped me learn more. When I write about something, I commit to completely understanding it and taking a deeper dive into it.</p><p>In this article, and (hopefully) the following ones as well, I'll share what I learned in Python within a week. Not only will this help me learn better, but I might learn from the readers as well if they point out anything wrong with what I've learned. This could help others who are interested in learning Python follow along this journey with me.</p><h2 id="quick-note">Quick Note</h2><p>The learning progress of every person is different. What I learn within a week may be more or less than what you'd learn in a week. That's fine for both of us.</p><p>Also, I already have knowledge and experience in a lot of other programming languages, so in most of these articles I'll be pointing out things that might be new to me or different than other languages.</p><h2 id="where-i-started">Where I Started</h2><p>I wanted to find a good place to start learning Python starting from the basics. I didn't want to just find a tutorial and start programming. I wanted to take the time to learn more about it.</p><p>After looking through different websites and <a href="https://capitaloneshopping.com/p/python-for-everybody-exploring-d/QMS8WS2C98">python courses</a> online that could help, I decided to learn from <a href="https://www.learnpython.org">learpython.org</a>. The topics seem to be divided up pretty well and each chapter had examples and an exercise at the end.</p><p>Up until the time I'm writing this I've finished until <a href="https://www.learnpython.org/en/Generators">Generators</a>.</p><h2 id="what-i-learned">What I Learned</h2><h3 id="indentation">Indentation</h3><p>In all programming languages I've used, code blocks are usually wrapped with curly braces <code class="language-text">{</code> and <code class="language-text">}</code>. For example, this in JavaScript:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span>x <span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"x is not 0"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>However, in Python, all code blocks are represented by just an indentation. So, if i were to write that same code block in Python it would be:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py"><span class="token keyword">if</span> x <span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"x is not 0"</span><span class="token punctuation">)</span></code></pre></div><h3 id="simultaneous-assignment">Simultaneous Assignment</h3><p>The naming for this might be incorrect but that's what I'm calling it for now.</p><p>In Python, you can assign multiple variables simultaneously like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py">a<span class="token punctuation">,</span>b <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span></code></pre></div><p>This line of code will set <code class="language-text">a</code> to <code class="language-text">1</code> and <code class="language-text">b</code> to <code class="language-text">2</code>.</p><h3 id="operators">Operators</h3><p>There are many operators that are common between Python and other languages. However, there were some that I haven't seen in other languages I know.</p><p>You can use <code class="language-text">**</code> to make a power relationship:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py">a <span class="token operator">=</span> <span class="token number">2</span> <span class="token operator">**</span> <span class="token number">3</span> <span class="token operator">//</span><span class="token number">8</span></code></pre></div><p>You can use the multiply operator <code class="language-text">*</code> on strings to repeat them <code class="language-text">n</code> times:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py">a <span class="token operator">=</span> <span class="token string">"hello"</span> <span class="token operator">*</span> <span class="token number">3</span> <span class="token operator">//</span>hellohellohello</code></pre></div><p>You can also use the multiply operator <code class="language-text">*</code> on lists (which are basically arrays in Python) to repeat them as well:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py">a <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token operator">*</span> <span class="token number">3</span> <span class="token operator">//</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span></code></pre></div><h3 id="string-formatting">String Formatting</h3><p>To format strings and add variables inside strings, you can use the <code class="language-text">%</code> operator in the string followed by a letter depending on the type of the variable you're inserting in the string.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py"><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"I am %d years old"</span> <span class="token operator">%</span> age<span class="token punctuation">)</span></code></pre></div><p><code class="language-text">%d</code> is used for integers, <code class="language-text">%s</code> for strings, <code class="language-text">%f</code> for float numbers, and <code class="language-text">%.nf</code> is a float number with <code class="language-text">n</code> places following the decimal.</p><h3 id="slicing-strings">Slicing Strings</h3><p>The brackets <code class="language-text">[]</code> are usually used with Arrays to refer to an item at a certain index. It's also used in some languages to access a character at a certain index in a string.</p><p>However, in Python, you can also use the brackets <code class="language-text">[]</code> with strings to take substrings of them. If you use the notation <code class="language-text">[n:m]</code> it will take a slice of the string starting from the index <code class="language-text">n</code> till the index <code class="language-text">m</code>.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py">x <span class="token operator">=</span> <span class="token string">"My name is Shahed"</span> <span class="token keyword">print</span><span class="token punctuation">(</span>x<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">//</span>name <span class="token keyword">is</span></code></pre></div><p>You can also use the notation <code class="language-text">[n:m:x]</code>, where <code class="language-text">x</code> is the number of steps to take when moving from index <code class="language-text">n</code> till index <code class="language-text">m</code>. When you use the notation <code class="language-text">[n:m]</code> it sets <code class="language-text">x</code> to 1 by default. <code class="language-text">x</code> can also be a negative value if you want to slice the string in reverse.</p><h3 id="boolean-operators">Boolean Operators</h3><p>Most languages use <code class="language-text">&&</code> to specify an "and" condition, and <code class="language-text">||</code> to specify an "or" condition.</p><p>In Python, you use <code class="language-text">and</code> for "and" and <code class="language-text">or</code> for "or". This is part of what makes Python human-readable.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py"><span class="token keyword">if</span> x <span class="token operator">==</span> <span class="token number">2</span> <span class="token keyword">and</span> y <span class="token operator">==</span> <span class="token number">3</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"x is 2 and y is 3"</span><span class="token punctuation">)</span></code></pre></div><p>Other operators are <code class="language-text">in</code> to check if an item is in an iterable object like a list, <code class="language-text">is</code> to check if 2 variables match in both value and reference, and <code class="language-text">not</code> to negate a boolean expression.</p><h3 id="else-in-loops">Else in Loops</h3><p><code class="language-text">else</code> is usually used with if conditions, where you perform an action if the condition is not true.</p><p>In Python, <code class="language-text">else</code> can be used with loops to perform an action when the condition of the loop fails.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="py"><pre class="language-py"><code class="language-py"><span class="token keyword">for</span> i <span class="token keyword">in</span> <span class="token builtin">range</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"i is less than 5"</span><span class="token punctuation">)</span> <span class="token keyword">else</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"i is greater than 5"</span><span class="token punctuation">)</span></code></pre></div><p>If you use <code class="language-text">break</code> inside the loop, then the <code class="language-text">else</code> block won't be executed. If you use <code class="language-text">continue</code> inside the loop, the <code class="language-text">else</code> block will be executed.</p><h3 id="init-function-in-classes">init Function in Classes</h3><p>In Python, the function <code class="language-text">__init__</code> in a class is the function that is first called when the class is created. It's the equivalent of the <code class="language-text">constructor</code> function in other languages.</p><h3 id="modules">Modules</h3><p>Each Python file that you create can be used as a module in other Python files. This allows you to use the functions or variables that are in that module.</p><p>To import a module:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python"><span class="token keyword">import</span> user</code></pre></div><p>Where <code class="language-text">user</code> is a file in the same directory with the name <code class="language-text">user.py</code></p><p>You can then access functions in that module using the <code class="language-text">.</code> notation:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python">user<span class="token punctuation">.</span>create<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre></div><p>Alternatively, you can import the function directly:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python"><span class="token keyword">from</span> user <span class="token keyword">import</span> create</code></pre></div><p>You can also import all objects in the module:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python"><span class="token keyword">from</span> user <span class="token keyword">import</span> <span class="token operator">*</span></code></pre></div><p>You can then use the objects directly:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python">create<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre></div><p>In addition, you can import modules with aliases:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python"><span class="token keyword">import</span> user <span class="token keyword">as</span> my_user</code></pre></div><h3 id="packages">Packages</h3><p>Packages are directories that hold other packages and modules. Each package should include the file <code class="language-text">__init__.py</code>, even if it's empty. It's used to indicate that the current directory is a package.</p><p>Modules can be imported from inside that package. For example, if you create the directory <code class="language-text">blog</code> and it has the <code class="language-text">user</code> module inside it, you can import it like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python"><span class="token keyword">import</span> blog<span class="token punctuation">.</span>user</code></pre></div><p>Or alternatively:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python"><span class="token keyword">from</span> blog <span class="token keyword">import</span> user</code></pre></div><p>By default, all modules inside a package can be imported. You can specify which modules can be accessed in a package by assigning the <code class="language-text">__all__</code> variable in <code class="language-text">__init__</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python">__all__ <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"user"</span><span class="token punctuation">]</span></code></pre></div><h3 id="numpy-arrays">Numpy Arrays</h3><p>Numpy arrays are like lists, but they are more fast and efficient. Using Numpy arrays you can easily perform a lot of tedious tasks.</p><p>For example, you can perform operations on all elements in a Numpy array:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python">np_array <span class="token operator">=</span> np<span class="token punctuation">.</span>array<span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span> np_array <span class="token operator">=</span> np_array <span class="token operator">*</span> <span class="token number">2</span> <span class="token operator">//</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">]</span></code></pre></div><p>You can also use <code class="language-text">[]</code> to take a subset of items in the Numpy array. For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python">np_array <span class="token operator">=</span> np<span class="token punctuation">.</span>array<span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span> np_array<span class="token punctuation">[</span>np_array <span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">//</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span></code></pre></div><p>Where <code class="language-text">np_array > 1</code> will return a new Numpy array but instead of the original values it will be either <code class="language-text">True</code> or <code class="language-text">False</code> based on whether each element satisfies the condition or not. If you then pass it as an index to <code class="language-text">np_array</code> it will return a Numpy array with only the elements that test true for that condition.</p><h3 id="pandas-dataframe">Pandas DataFrame</h3><p>DataFrames in Pandas allow you to store data in a table-like structure where there are columns and rows.</p><p>DataFrames can be created from dictionaries. They can also be created from CSV files.</p><p>You can access the data using a column name as an index:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python">dataframe<span class="token punctuation">[</span><span class="token string">"name"</span><span class="token punctuation">]</span></code></pre></div><p>This will return the data as a Pandas Series. You can use double brackets to have it be returned as a DataFrame:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python">dataframe<span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token string">"name"</span><span class="token punctuation">]</span><span class="token punctuation">]</span></code></pre></div><p>You can also return multiple columns or indices:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python">dataframe<span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token string">"name"</span><span class="token punctuation">,</span> <span class="token string">"age"</span><span class="token punctuation">]</span><span class="token punctuation">]</span></code></pre></div><p>Another way of getting a set of data from the DataFrame is using <code class="language-text">loc</code> and <code class="language-text">iloc</code>, where <code class="language-text">loc</code> accesses the data using a label index, while <code class="language-text">iloc</code> accesses the data using a numeric index. It's helpful if you have a specific row and column to access.</p><h3 id="generators">Generators</h3><p>Generators are used to implement iterators. They are functions that use the keyword <code class="language-text">yield</code> to return an iterable set of items.</p><p>When you run an iteration over the generator function, the generator starts. Everytime the <code class="language-text">yield</code> keyword is reached, the value is returned as the value for the current iteration.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python"><span class="token keyword">def</span> <span class="token function">age</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">for</span> i <span class="token keyword">in</span> <span class="token builtin">range</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">yield</span> <span class="token string">"I am %d years old"</span> <span class="token operator">%</span> i <span class="token keyword">for</span> <span class="token builtin">str</span> <span class="token keyword">in</span> age<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token builtin">str</span><span class="token punctuation">)</span></code></pre></div><p>This will print:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python">I am <span class="token number">0</span> years old I am <span class="token number">1</span> years old I am <span class="token number">2</span> years old I am <span class="token number">3</span> years old I am <span class="token number">4</span> years old</code></pre></div><h2 id="where-next">Where Next?</h2><p>There are still more chapters to go through in learnpython.org, however, I think I want to practice solving some problems as well.</p><p>A platform that I found good reviews for among Python learners and developers is <a href="https://checkio.org">CheckiO</a>. So, I'll probably start learning through this platform while also continuing on with some of the other chapters.</p><p>If you have any ideas of how I should continue in my journey of learning Python or find anything wrong with this article, please let me know!</p>]]></content:encoded></item><item><title><![CDATA[Cross-Post CLI Tool: New Features and Fixes]]></title><description><![CDATA[I'll be sharing some of the features and fixes the new version of cross-post-blog includes.]]></description><link>https://blog.shahednasser.com/cross-post-cli-tool-new-features-and-fixes/</link><guid isPermaLink="false">Ghost__Post__621c858deb81df0613580535</guid><category><![CDATA[Projects]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 28 Feb 2022 09:05:19 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/3992c44a6f85cbb0e7f336ddf13d9f6e/Cross-Post-CLI-Tool-New-Features-and-Fixes.webp" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/3992c44a6f85cbb0e7f336ddf13d9f6e/Cross-Post-CLI-Tool-New-Features-and-Fixes.webp" alt="Cross-Post CLI Tool: New Features and Fixes"/><p>Almost a year ago, I wrote about how <a href="https://blog.shahednasser.com/i-created-a-cli-to-cross-post-your-articles-on-dev-hashnode-and-medium">I created a CLI tool</a> to <a href="https://github.com/shahednasser/cross-post">cross-post</a> articles to Dev.to, Hashnode, and Medium. I created the tool because it made the process easier for me, but I also received a lot of feedback from other writers about how it was helpful for them.</p><p>Since then, I haven't been able to maintain it much due to my busy schedule. Now, I'm taking more time to commit to it and improve it with the help of the community.</p><p>On Monday, the 28th of February, I pushed out a new release of <code class="language-text">cross-post-blog</code> with the version <code class="language-text">1.3.0</code>. I'll be sharing some of the features and fixes it includes. You can also check out the <a href="https://github.com/shahednasser/cross-post">GitHub repository</a> for more information about the library.</p><p>If you're reading this article on Dev.to, Hashnode, or Medium, then it is reposted from <a href="https://blog.shahednasser.com/cross-post-cli-tool-new-features-and-fixes/">my own blog</a> using the Cross-Post CLI tool!</p><h2 id="posting-from-local-files">Posting From Local Files</h2><p>Based on demand from some of the developers using this library, I've now added the ability to post directly from a local file instead of a public URL. To do that, you simply need to add the <code class="language-text">-l</code> or <code class="language-text">--local</code> option to your command.</p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">cross-post run /path/to/test.md -l</code></pre></div><p>This will post a local file <code class="language-text">test.md</code> to all of the platforms.</p><p>You can also use it with all of the <a href="https://github.com/shahednasser/cross-post#cross-posting-your-articles">options you previously used</a>.</p><h2 id="changed-markdown-converter">Changed Markdown Converter</h2><p>Each of the platforms requires you to send the content of your article to post in Markdown format. So, when you pass a URL to the command, the content of the article on that page is converted to Markdown before submitting it to the platform you want to post on.</p><p>I previously was using <a href="https://www.npmjs.com/package/node-html-markdown"><code class="language-text">node-html-markdown</code></a>. It worked fine in terms of functionality. However, there were some issues related to how it <a href="https://github.com/shahednasser/cross-post/issues/14">parsed code blocks</a>.</p><p>The new version is now using <a href="https://www.npmjs.com/package/turndown"><code class="language-text">turndown</code></a> instead, which does a better job of parsing code blocks. Your articles should now be posted to the different platforms almost exactly as you have it posted on your own blog.</p><h2 id="added-title-selector">Added Title Selector</h2><p>Previously, you could set a default article and image selectors in the configuration. You could also override those configurations in the <code class="language-text">run</code> command.</p><p>N0w, you can also set the default title selector in your configuration:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">cross-post config titleConfig</code></pre></div><p>Or, pass it as an option <code class="language-text">-ts</code> or <code class="language-text">--title-selector</code> to the <code class="language-text">run</code> command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">cross-post run <span class="token operator"><</span>url<span class="token operator">></span> -ts .post-full-title</code></pre></div><h2 id="upcoming-features">Upcoming Features</h2><p>I'll be working from now on to improve the tool and add new features, either from the request of developers using this tool or from my own experience using it. For example, a feature that has been requested is the ability to <a href="https://github.com/shahednasser/cross-post/issues/20">update posts</a>.</p><p>I'm also going to look into adding new platforms to enable posting to. If you have any platform in mind that you think would be good to add please do let me know!</p><h2 id="how-to-install-or-update">How to Install or Update</h2><p>If you want to install and start using Cross-Post or update your version you can install it with NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i -g cross-post-blog</code></pre></div><p>Please check the <a href="https://github.com/shahednasser/cross-post">README</a> for more information on installing and using this tool.</p><h2 id="contribution">Contribution</h2><p>At the moment, there's no contribution guideline added in the repository (I'm working on that). However, if you would like to contribute to any of the <a href="https://github.com/shahednasser/cross-post/issues">existing issues</a> or add new features, then please don't hesitate!</p>]]></content:encoded></item><item><title><![CDATA[How to Read and Write CSV Files Using Node.js and Express]]></title><description><![CDATA[In this tutorial, you'll learn how you can read and write CSV files using Node.js and Express.]]></description><link>https://blog.shahednasser.com/how-to-read-and-write-csv-files-using-node-js-and-express/</link><guid isPermaLink="false">Ghost__Post__620a3586eb81df0613580321</guid><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 22 Feb 2022 10:35:58 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/196931c9c84e46c7a3f4d7fc5de2508b/How-to-Read-and-Write-CSV-Files-Using-Node.js-and-Express.webp" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/196931c9c84e46c7a3f4d7fc5de2508b/How-to-Read-and-Write-CSV-Files-Using-Node.js-and-Express.webp" alt="How to Read and Write CSV Files Using Node.js and Express"/><p>Node.js can be used to build a variety of apps and websites. It's most popularly used with <a href="https://expressjs.com">Express</a> to create a server for your websites and apps.</p><p>In this tutorial, you'll learn how you can read and write CSV files using Node.js and Express. You can find the full code for this tutorial in<a href="https://github.com/shahednasser/node-csv-tutorial"> this GitHub Repository</a>.</p><h2 id="project-setup">Project Setup</h2><p>You'll start by setting up the server with NPM. </p><p>Run the following command to create a new directory and initialize the project with NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> node-csv <span class="token function">npm</span> init -y</code></pre></div><p>Then, you need to install the dependencies needed for the project:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i express body-parser nodemon</code></pre></div><p>This will install <code class="language-text">express</code> to create a server, <code class="language-text">body-parser</code> to parse the body of the requests, and <code class="language-text">nodemon</code> to make sure that the server restarts whenever there are new changes in the files.</p><p>After that, create <code class="language-text">index.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'express'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> bodyParser <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'body-parser'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> port <span class="token operator">=</span> <span class="token number">3000</span> app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>bodyParser<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>express<span class="token punctuation">.</span><span class="token function">static</span><span class="token punctuation">(</span><span class="token string">'public'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span>port<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">App listening on port </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>port<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>This will initialize your server.</p><p>Finally, add the <code class="language-text">start</code> script command in <code class="language-text">package.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"start"</span><span class="token operator">:</span> <span class="token string">"nodemon index.js"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>Now, you can start the server by running the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>This will start the server on <code class="language-text">localhost:3000</code>.</p><h2 id="write-csv-files">Write CSV Files</h2><p>The first part of this tutorial will go over how you can write CSV files.</p><p>For this, you'll use the CSV Stringify library that takes a set of data and turns it into a string in the CSV format. You can then use the string to write a CSV file.</p><p>In this tutorial, you'll create a page where the user can dynamically create a table to be transformed into a CSV file that they can download.</p><p>Start by installing the necessary dependency for this functionality:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i csv-stringify</code></pre></div><p>Create the file <code class="language-text">public/create.html</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>IE=edge<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">integrity</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3<span class="token punctuation">"</span></span> <span class="token attr-name">crossorigin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>anonymous<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://unpkg.com/tabulator-tables/dist/css/tabulator.min.css<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Create CSV<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>container py-4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Create CSV<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h2</span><span class="token punctuation">></span></span>Add Columns<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h2</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>column<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>columnName<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Column Name<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn-primary mt-1<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>addColumn<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Add<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mt-3<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Column Data<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h2</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn-primary mb-3<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>addRow<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Add Row<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>csvTable<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn-primary mt-3<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submitForm<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Create CSV<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js<span class="token punctuation">"</span></span> <span class="token attr-name">integrity</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p<span class="token punctuation">"</span></span> <span class="token attr-name">crossorigin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>anonymous<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"/><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/javascript<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://unpkg.com/tabulator-tables/dist/js/tabulator.min.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"/><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">const</span> columnNameInput <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'columnName'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> addColumnButton <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'addColumn'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> addRowButton <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'addRow'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> submitFormButton <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'submitForm'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> table <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Tabulator</span><span class="token punctuation">(</span><span class="token string">"#csvTable"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">height</span><span class="token operator">:</span><span class="token string">"300px"</span><span class="token punctuation">,</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">//assign data to table</span> <span class="token literal-property property">movableColumns</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">addRowPos</span><span class="token operator">:</span> <span class="token string">"bottom"</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> addColumnButton<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> name <span class="token operator">=</span> columnNameInput<span class="token punctuation">.</span>value <span class="token operator">?</span> columnNameInput<span class="token punctuation">.</span>value<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>name<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Please add a name"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> table<span class="token punctuation">.</span><span class="token function">addColumn</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">title</span><span class="token operator">:</span> name<span class="token punctuation">,</span> <span class="token literal-property property">field</span><span class="token operator">:</span> name<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">editableTitle</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">editor</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> columnNameInput<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> addRowButton<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> table<span class="token punctuation">.</span><span class="token function">addRow</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> submitFormButton<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> data <span class="token operator">=</span> table<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'/create'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">'POST'</span><span class="token punctuation">,</span> <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span> data <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'Content-Type'</span><span class="token operator">:</span> <span class="token string">'application/json'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">blob</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">blob</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> fileURL <span class="token operator">=</span> <span class="token constant">URL</span><span class="token punctuation">.</span><span class="token function">createObjectURL</span><span class="token punctuation">(</span>blob<span class="token punctuation">)</span> <span class="token keyword">const</span> a <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'a'</span><span class="token punctuation">)</span> a<span class="token punctuation">.</span>href <span class="token operator">=</span> fileURL a<span class="token punctuation">.</span>download <span class="token operator">=</span> <span class="token string">"file.csv"</span> a<span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token function">alert</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>message<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre></div><p>This page will allow the user to create a CSV file. For simplicity, you're using <a href="https://getbootstrap.com">Bootstrap</a> for easy styling and <a href="http://tabulator.info">Tabulator</a> to easily create a table with modifiable columns and rows.</p><p>You show the user an input to add columns with a name, and a button to add rows. After the user creates the CSV file using the table. They can click on the "Create CSV" button. This will take the data from the table and send a <code class="language-text">POST</code> request to the <code class="language-text">create</code> endpoint (which you'll create next) with the data. Then, the received file will be downloaded.</p><p>Next, you'll create the <code class="language-text">create</code> endpoint. Open <code class="language-text">index.js</code> and add the following <code class="language-text">require</code> statement at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> stringify <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'csv-stringify'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>stringify</code></pre></div><p>You'll use <code class="language-text">fs</code> to create the CSV file and <code class="language-text">stringify</code> from the <code class="language-text">csv-stringify</code> library.</p><p>Next, add the following new endpoint to your server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">'/create'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> data <span class="token operator">=</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>data <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>data <span class="token operator">||</span> <span class="token operator">!</span>data<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">400</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'Please enter at least 1 row'</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">stringify</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">header</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">err<span class="token punctuation">,</span> str</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token string">'./files/'</span> <span class="token operator">+</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">'.csv'</span> <span class="token comment">//create the files directory if it doesn't exist</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>fs<span class="token punctuation">.</span><span class="token function">existsSync</span><span class="token punctuation">(</span><span class="token string">'./files'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> fs<span class="token punctuation">.</span><span class="token function">mkdirSync</span><span class="token punctuation">(</span><span class="token string">'./files'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> fs<span class="token punctuation">.</span><span class="token function">writeFile</span><span class="token punctuation">(</span>path<span class="token punctuation">,</span> str<span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">400</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'An error occurred'</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> res<span class="token punctuation">.</span><span class="token function">download</span><span class="token punctuation">(</span>path<span class="token punctuation">,</span> <span class="token string">'file.csv'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>This will first validate the data sent. Then, you'll use the <code class="language-text">stringify</code> function to create the CSV string. This function takes the data to be stringified as the first parameter, an object of <a href="https://csv.js.org/stringify/options/">options</a> as the second parameter, and a callback function as the third.</p><p>The <code class="language-text">header</code> option makes sure to include the column names as the header of the CSV file.</p><p>In the callback function, you create a file using <code class="language-text">fs</code> in the directory <code class="language-text">files</code> using <code class="language-text">writeFile</code>. The file will contain the CSV string created by <code class="language-text">stringify</code>. In the callback function of <code class="language-text">writeFile</code> you return the CSV file for download.</p><p>Now, if you run the server (if it's not already running) and go to <code class="language-text">localhost:3000/create.html</code> you'll see the page you created earlier in <code class="language-text">public/create.html</code>. Try adding a few columns and rows into the table.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-02-12-at-7.28.59-PM.png.jpeg" class="kg-image" alt="How to Read and Write CSV Files Using Node.js and Express" loading="lazy" width="880" height="444"/></figure><p>Once you're done, click the "Create CSV" button. This will send the data to the server at the <code class="language-text">create</code> endpoint you created. Then, the endpoint will return a file for download which will then initiate a download in the user's browser.</p><h2 id="read-a-csv-file">Read a CSV File</h2><p>In this section, you'll learn how to read a CSV file in Node.js and Express. The user will upload a CSV file. </p><p>Then, you'll pass the file along to the server that will parse it and return the data in JSON format. You'll then use Tabulator to show the CSV file's data.</p><p>To parse a CSV file, you'll use <a href="https://csv.js.org/parse/">CSV Parse</a>. You'll also use Express Multer Middleware to handle file upload.</p><p>Start by downloading the necessary dependencies:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i multer csv-parse</code></pre></div><p>N0w, create the file <code class="language-text">public/read.html</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>IE=edge<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Read CSV<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">integrity</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3<span class="token punctuation">"</span></span> <span class="token attr-name">crossorigin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>anonymous<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://unpkg.com/tabulator-tables/dist/css/tabulator.min.css<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>container py-4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Read CSV<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Choose file to read<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn-primary mt-2<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submitFile<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Read<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mt-2<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>csvTable<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js<span class="token punctuation">"</span></span> <span class="token attr-name">integrity</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p<span class="token punctuation">"</span></span> <span class="token attr-name">crossorigin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>anonymous<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"/><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/javascript<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://unpkg.com/tabulator-tables/dist/js/tabulator.min.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"/><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">const</span> fileInput <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'file'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> submitFile <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'submitFile'</span><span class="token punctuation">)</span> <span class="token keyword">let</span> file <span class="token operator">=</span> <span class="token keyword">null</span> fileInput<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'change'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> file <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>files<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> submitFile<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>file <span class="token operator">||</span> file<span class="token punctuation">.</span>type <span class="token operator">!==</span> <span class="token string">'text/csv'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'Please choose a CSV file'</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> formData <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FormData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> formData<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">'file'</span><span class="token punctuation">,</span> file<span class="token punctuation">)</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'/read'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">'POST'</span><span class="token punctuation">,</span> <span class="token literal-property property">body</span><span class="token operator">:</span> formData <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> data <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>data<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> columns <span class="token operator">=</span> data<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token keyword">const</span> rows <span class="token operator">=</span> data<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">arr</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> columns<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">column<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> obj<span class="token punctuation">[</span>column<span class="token punctuation">]</span> <span class="token operator">=</span> arr<span class="token punctuation">[</span>index<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">return</span> obj <span class="token punctuation">}</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>rows<span class="token punctuation">,</span> columns<span class="token punctuation">)</span> <span class="token keyword">const</span> table <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Tabulator</span><span class="token punctuation">(</span><span class="token string">"#csvTable"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">height</span><span class="token operator">:</span><span class="token string">"300px"</span><span class="token punctuation">,</span> <span class="token literal-property property">data</span><span class="token operator">:</span> rows<span class="token punctuation">,</span> <span class="token literal-property property">autoColumns</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'The CSV is empty'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">alert</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre></div><p>Just like <code class="language-text">create.html</code> this file uses Bootstrap for easy styling and Tabulator to easily show the CSV file in a table.</p><p>The page shows a file input for the user with a button to upload the CSV file. When the user chooses a file and clicks the button, the file is uploaded to the server at the endpoint <code class="language-text">read</code> (which you'll create next). Then, using the data the server creates you'll show the data in a Tabulator table.</p><p>Now, you need to add the <code class="language-text">read</code> endpoint.</p><p>In <code class="language-text">index.js</code>, add the following require statements at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> parse <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'csv-parse'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>parse <span class="token keyword">const</span> os <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'os'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> multer <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'multer'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> upload <span class="token operator">=</span> <span class="token function">multer</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">dest</span><span class="token operator">:</span> os<span class="token punctuation">.</span><span class="token function">tmpdir</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Notice that you also initialize multer and specify the destination as the <code class="language-text">tmp</code> directory of the operating system. This is because you don't need to actually store the file anywhere for this tutorial.</p><p>Also, note that you'll need to use <code class="language-text">fs</code> as well. So, if you didn't follow along with the previous section make sure to require it here as well.</p><p>Then, add the following new endpoint:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">'/read'</span><span class="token punctuation">,</span> upload<span class="token punctuation">.</span><span class="token function">single</span><span class="token punctuation">(</span><span class="token string">'file'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> file <span class="token operator">=</span> req<span class="token punctuation">.</span>file <span class="token keyword">const</span> data <span class="token operator">=</span> fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span>file<span class="token punctuation">.</span>path<span class="token punctuation">)</span> <span class="token function">parse</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err<span class="token punctuation">,</span> records</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">400</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'An error occurred'</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">data</span><span class="token operator">:</span> records<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>You first read the file using <code class="language-text">fs.readFileSync</code>. Then, you parse the file data using <code class="language-text">parse</code> from <code class="language-text">csv-parse</code>. </p><p>If an error occurs, you return an error message to the user. Otherwise, you return the data.</p><p>Run the server if it's not running already then go to <code class="language-text">localhost:3000/read.html</code>. You'll see a file input with a button.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-02-12-at-8.40.33-PM.png.jpeg" class="kg-image" alt="How to Read and Write CSV Files Using Node.js and Express" loading="lazy" width="880" height="161"/></figure><p>Choose a CSV file then click read. The file data will be displayed in a table using Tabulator.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-02-12-at-8.52.52-PM.png.jpeg" class="kg-image" alt="How to Read and Write CSV Files Using Node.js and Express" loading="lazy" width="880" height="340"/></figure><h2 id="conclusion">Conclusion</h2><p>In this tutorial, you learned how you can read and write CSV files in Node.js and Express. You used the libraries <a href="https://csv.js.org/parse/">CSV Parse</a> and <a href="https://csv.js.org/stringify/">CSV Stringify</a> to do that. Please check out each of their documentation for better understanding of how it works and what more you can do with them.</p>]]></content:encoded></item><item><title><![CDATA[How to Style a Scrollbar with CSS]]></title><description><![CDATA[In this article, you'll learn how you can style a scrollbar with CSS and which pseudo-element selectors you need to use.]]></description><link>https://blog.shahednasser.com/how-to-style-a-scrollbar-with-css/</link><guid isPermaLink="false">Ghost__Post__61fa773460a9ab05cc5e69de</guid><category><![CDATA[CSS]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 15 Feb 2022 10:00:19 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/9413f31144928401d71424aa8a4a37e4/How-to-Style-a-Scrollbar-with-CSS.webp" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/9413f31144928401d71424aa8a4a37e4/How-to-Style-a-Scrollbar-with-CSS.webp" alt="How to Style a Scrollbar with CSS"/><p>Scrollbars usually are styled based on the browser or operating system the website is viewed in. This means that your website's scrollbar will not have a unified look across platforms. Although this is generally fine, it's cool to have a good-looking scrollbar regardless of what browser the user is using!</p><p>However, styling the scrollbar can be tricky in CSS. You'll need to use pseudo-element selectors.</p><p>In this article, you'll learn how you can style a scrollbar with CSS and which pseudo-element selectors you need to use.</p><h2 id="pseudo-element-selectos-compatibility">Pseudo-Element Selectos Compatibility</h2><p>The pseudo-element selectors mentioned in this tutorial will only work on <a href="https://en.wikipedia.org/wiki/List_of_web_browsers#WebKit-based">Webkit</a> browsers. So, it will work on most modern browsers like Chrome and Safari.</p><p>However, they will not work on Firefox. Alternatively, you can use the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-width">scrollbar-width</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-color">scrollbar-color</a> properties.</p><h2 id="webkit-scrollbar">::-webkit-scrollbar</h2><p>This pseudo-element selector is the base selector you need to use when customizing your scrollbar. It is used to specify the width of a scrollbar.</p><p>Note that if this selector is used on a specific element (not the scrollbar of the entire page), then you need to specify <code class="language-text">overflow: scroll;</code> on the element, or else the scrollbar won't show.</p><p>Apply the following styling to set the width of the page's scrollbar:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">::-webkit-scrollbar</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 30px<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>If you try this out, you'll notice that no scroll bar appears. This is because you need to add a background color for the scrollbar track or handle.</p><h2 id="webkit-scrollbar-thumb">::-webkit-scrollbar-thumb</h2><p>You can use this pseudo-element selector to style the thumb of the scrollbar. This means the part you can drag to scroll the page.</p><p>For example, you can use this selector to make its background red and give it a border-radius:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">::-webkit-scrollbar-thumb</span> <span class="token punctuation">{</span> <span class="token property">background</span><span class="token punctuation">:</span> #ef4444<span class="token punctuation">;</span> <span class="token property">border-radius</span><span class="token punctuation">:</span> 20px<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-02-02-at-2.43.24-PM-1.png.jpeg" class="kg-image" alt="How to Style a Scrollbar with CSS" loading="lazy" width="228" height="1640"/></figure><h2 id="webkit-scrollbar-track">::-webkit-scrollbar-track</h2><p>You can use this pseudo-element selector to style the track. This is the part that is below the thumb.</p><p>Another pseudo-element selector that can be used is <code class="language-text">::-webkit-scrollbar-track-piece</code>, which is the part of the scrollbar not covered by the handler. The <code class="language-text">::-webkit-scrollbar-track-piece</code> is on a higher layer than <code class="language-text">::-webkit-scrollbar-track</code>.</p><p>For example, you can use it to add a background color to the track:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">::-webkit-scrollbar-track</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> #fca5a5<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-02-02-at-3.19.51-PM.png.jpeg" class="kg-image" alt="How to Style a Scrollbar with CSS" loading="lazy" width="358" height="428"/></figure><h2 id="webkit-scrollbar-button">::-webkit-scrollbar-button</h2><p>You can use this to style the up and down (or left and right for horizontal scrollbars) buttons.</p><p>This will apply styling to all scrollbar buttons. This means it will apply the styling for both the horizontal and vertical scrollbar buttons.</p><p>To apply specific styling for specific buttons here's what you need to use:</p><ol><li><code class="language-text">::-webkit-scrollbar-button:vertical:start</code>: This is for the up button in the vertical scrollbar.</li><li><code class="language-text">::-webkit-scrollbar-button:vertical:end</code>: This is for the down button in the vertical scrollbar.</li><li><code class="language-text">::-webkit-scrollbar-button:horizontal:start</code>: This is for the left button in the horizontal scrollbar.</li><li><code class="language-text">::-webkit-scrollbar-button:horizontal:end</code>: This is for the right button in the horizontal scrollbar.</li></ol><p>Additionally, each button has a <code class="language-text">:increment</code> and <code class="language-text">:decrement</code> selector.</p><p>In this example, I'll add styling for the buttons of a vertical scrollbar:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">::-webkit-scrollbar-button</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> #b91c1c<span class="token punctuation">;</span> <span class="token property">background-repeat</span><span class="token punctuation">:</span> no-repeat<span class="token punctuation">;</span> <span class="token property">background-size</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span> <span class="token property">background-position</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">::-webkit-scrollbar-button:vertical:start:increment</span> <span class="token punctuation">{</span> <span class="token property">background-image</span><span class="token punctuation">:</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'https://upload.wikimedia.org/wikipedia/commons/7/7e/Chevron-up.svg'</span><span class="token punctuation">)</span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">::-webkit-scrollbar-button:vertical:start:decrement</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">::-webkit-scrollbar-button:vertical:end:increment</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">::-webkit-scrollbar-button:vertical:end:decrement</span> <span class="token punctuation">{</span> <span class="token property">background-image</span><span class="token punctuation">:</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span><span class="token string url">'https://upload.wikimedia.org/wikipedia/commons/e/ee/Chevron-down.svg'</span><span class="token punctuation">)</span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>The properties in <code class="language-text">::-webkit-scrollbar-button</code> will apply for all scrollbar buttons. In the example, I add a background color. I also set the display to <code class="language-text">block</code> because some browsers or operating systems might have it hidden by default. Finally, I add background-related properties because I will use background images to show the up and down icons.</p><p>The <code class="language-text">::-webkit-scrollbar-button:vertical:start:increment</code> selector will target the increment part of the up button of the vertical scrollbar. I use it to show the icon as a background image.</p><p>The <code class="language-text">::-webkit-scrollbar-button:vertical:start:decrement</code> selector will target the decrement part of the up button of the vertical scrollbar. I use it to hide the decrement part as it is not necessary for the up button.</p><p>The <code class="language-text">::-webkit-scrollbar-button:vertical:end:increment</code> selector will target the increment part of the down button of the vertical scrollbar. I use it to hide the increment part as it is not necessary for the down button.</p><p>The <code class="language-text">::-webkit-scrollbar-button:vertical:end:decrement</code> selector will target the decrement part of the down button of the vertical scrollbar. I use it to show the icon as a background image.</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-02-02-at-3.41.17-PM.png.jpeg" width="152" height="174" loading="lazy" alt="How to Style a Scrollbar with CSS"/></div><div class="kg-gallery-image"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-02-02-at-3.41.25-PM.png.jpeg" width="238" height="170" loading="lazy" alt="How to Style a Scrollbar with CSS"/></div></div></div></figure><h2 id="webkit-scrollbar-corner">::-webkit-scrollbar-corner</h2><p>This pseudo-element selector is used to style the space between the vertical and horizontal scrollbars.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-02-02-at-3.54.09-PM.png.jpeg" class="kg-image" alt="How to Style a Scrollbar with CSS" loading="lazy" width="170" height="130"/></figure><p>For example, you can use it to set different background color:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">::-webkit-scrollbar-corner</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> #7f1d1d<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-02-02-at-3.56.09-PM.png.jpeg" class="kg-image" alt="How to Style a Scrollbar with CSS" loading="lazy" width="230" height="142"/></figure><h2 id="conclusion">Conclusion</h2><p>Scrollbars can be easily styled on your website using these pseudo-element selectors. You can style them to make sure they match your website's look and feel regardless of what platform your website is opened on.</p><p>As mentioned earlier, these selectors will only work on Webkit browsers. Please check out <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-scrollbar#browser_compatibility">MDN's browser compatibility table</a> for further information.</p>]]></content:encoded></item><item><title><![CDATA[How to Create a Notes App with Strapi v4 and React Native]]></title><description><![CDATA[In this tutorial, you'll learn how to create a Notes app with Strapi v4 and React Native.]]></description><link>https://blog.shahednasser.com/how-to-create-notes-app-with-strapi-v4-and-react-native/</link><guid isPermaLink="false">Ghost__Post__61f9452160a9ab05cc5e689a</guid><category><![CDATA[Strapi]]></category><category><![CDATA[React Native]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 08 Feb 2022 10:23:54 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/53fcf20de38e44c013aa2b39f34c0a28/How-to-Create-a-Notes-App-with-Strapi-v4-and-React-Native-5.webp" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/53fcf20de38e44c013aa2b39f34c0a28/How-to-Create-a-Notes-App-with-Strapi-v4-and-React-Native-5.webp" alt="How to Create a Notes App with Strapi v4 and React Native"/><p><a href="https://strapi.io">Strapi</a> is a headless CMS framework that allows you to integrate CMS functionalities into any of your technical stacks. This gives you more flexibility when choosing the different components that make up your project.</p><p>One of the many frameworks you can integrate Strapi to is <a href="https://reactnative.dev">React Native</a>. React Native is a cross-platform framework that allows you to write your code in JavaScript, then deploy it on Android and iOS.</p><p>In this tutorial, you'll learn how to create a Notes app with Strapi v4 and React Native. You'll be able to add notes on the Strapi backend. Then, you'll be able to view, edit, create, and delete notes in the React Native app.</p><p>You can find the code for this tutorial on <a href="https://github.com/shahednasser/strapi-react-native">this GitHub repository</a>.</p><h2 id="setup-strapi">Setup Strapi</h2><p>In your terminal, run the following command to install and setup Strapi:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-strapi-app@latest strapi --quickstart</code></pre></div><p>This will create a new directory called <code class="language-text">strapi</code>, and, once the installation is done, a new page will open in your default browser at the Strapi backend. It's usually at <code class="language-text">localhost:1337</code>.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-01-31-at-4.55.39-PM.png.jpeg" class="kg-image" alt="How to Create a Notes App with Strapi v4 and React Native" loading="lazy" width="880" height="1026"/></figure><p>You'll need to create an admin user. Once you're done, you'll be redirected to the admin dashboard.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-01-31-at-4.57.11-PM.png.jpeg" class="kg-image" alt="How to Create a Notes App with Strapi v4 and React Native" loading="lazy" width="880" height="479"/></figure><h3 id="create-content-types">Create Content-Types</h3><p>Click on <em>Content-Type Builder</em> on the sidebar. Then, click on <em>Create new collection type</em> under <em>Collection Types</em>.</p><p>In the pop-up, enter <code class="language-text">Note</code> for display name. Then click continue.</p><p>You'll create 3 fields:</p><ol><li><code class="language-text">title</code>: of type Text. Make sure to set it required in the Advanced Settings tab.</li><li><code class="language-text">content</code>: of type Rich Text. Make sure to set it required in the Advanced Settings tab.</li><li><code class="language-text">date</code>: of type Date. Make sure to select <code class="language-text">datetime</code> in the Type dropdown, and set it required in the Advanced Settings tab.</li></ol><p>You should have a Note collection type with the following fields:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-01-31-at-5.01.15-PM-1.png" class="kg-image" alt="How to Create a Notes App with Strapi v4 and React Native" loading="lazy" width="880" height="519"/></figure><p>Once you're done click <em>Save</em>.</p><h3 id="change-permissions">Change Permissions</h3><p>The next step is to change permissions so that you can access the notes from React Native.</p><p>Click on <em>Settings</em> in the sidebar, then go to <em>Roles</em> under <em>Users & Permissions Plugin</em>. You'll see two entries in the table. Click on the edit icon for the Public row.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-01-31-at-5.01.40-PM.png.jpeg" class="kg-image" alt="How to Create a Notes App with Strapi v4 and React Native" loading="lazy" width="880" height="500"/></figure><p>Then, scroll down. Under <em>Permissions</em>, click on <em>Note</em> to expand it, then select all permissions. Once you're done, click Save at the top right.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/Screen-Shot-2022-01-31-at-5.01.53-PM.png.jpeg" class="kg-image" alt="How to Create a Notes App with Strapi v4 and React Native" loading="lazy" width="880" height="780"/></figure><h2 id="setup-react-native">Setup React Native</h2><p>Next, you'll set up a React Native project.</p><p>First, you need to install the <a href="https://docs.expo.dev/workflow/expo-cli/">Expo CLI</a> if you don't have it installed:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i -g expo-cli</code></pre></div><p>Next, run the following command to create a new React Native project:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">expo init notes-app</code></pre></div><p>Choose <em>Blank</em> when asked about the type of project to create.</p><p>Once that is done, change to the newly created directory <code class="language-text">notes-app</code> and install dependencies with NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> notes-app <span class="token function">npm</span> i</code></pre></div><p>Now, you'll need to install the dependencies you'll need for this tutorial. First, start by installing some dependencies with Expo's CLI:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">expo <span class="token function">install</span> react-native-screens react-native-safe-area-context</code></pre></div><p>These dependencies are necessary to add <a href="https://reactnavigation.org">React Navigation</a>, which is a library that adds navigation capabilities between screens in your app.</p><p><em><a href="https://blog.shahednasser.com/react-native-navigation-tutorial">Suggested Read: React Native Navigation Tutorial.</a></em></p><p>Next, install the necessary dependencies with NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i react-native-paper @react-navigation/native @react-navigation/native-stack react-native-pell-rich-editor react-native-webview</code></pre></div><p>Here's what each dependency is for:</p><ol><li><code class="language-text">react-native-paper</code>: <a href="https://callstack.github.io/react-native-paper/index.html">React Native Paper</a> library to easily add styled-components in your app.</li><li><code class="language-text">@react-navigation/native @react-navigation/native-stack</code>: More libraries for React Navigation.</li><li><code class="language-text">react-native-pell-rich-editor</code>: a <a href="https://github.com/wxik/react-native-rich-editor">Rich Editor</a> element for React Native.</li><li><code class="language-text">react-native-webview</code>: required by <code class="language-text">react-native-pell-rich-editor</code>.</li></ol><h2 id="create-home-screen">Create Home Screen</h2><p>The home screen displays a list of notes with just the title and the date. It will also have a <code class="language-text">+</code> button at the top right to add notes.</p><p>Create the file <code class="language-text">screens/HomeScreen.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> axios <span class="token keyword">from</span> <span class="token string">"axios"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useEffect<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> FlatList<span class="token punctuation">,</span> View <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-native"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Caption<span class="token punctuation">,</span> List<span class="token punctuation">,</span> Snackbar <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-native-paper"</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">HomeScreen</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> navigation <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>notes<span class="token punctuation">,</span> setNotes<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>loading<span class="token punctuation">,</span> setLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>error<span class="token punctuation">,</span> setError<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">loadNotes</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> subscribe <span class="token operator">=</span> navigation<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token string">'focus'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">loadNotes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> subscribe<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">function</span> <span class="token function">loadNotes</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'http://<IP>:1337/api/notes'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> data <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setNotes</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setError</span><span class="token punctuation">(</span><span class="token string">'An error occurred, please try again later.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>View<span class="token operator">></span> <span class="token punctuation">{</span><span class="token operator">!</span>loading <span class="token operator">&&</span> <span class="token operator">!</span>notes<span class="token punctuation">.</span>length <span class="token operator">&&</span> <span class="token operator"><</span>Caption style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token literal-property property">textAlign</span><span class="token operator">:</span> <span class="token string">'center'</span><span class="token punctuation">,</span> <span class="token literal-property property">marginTop</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span>You have no notes<span class="token operator"><</span><span class="token operator">/</span>Caption<span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator"><</span>FlatList data<span class="token operator">=</span><span class="token punctuation">{</span>notes<span class="token punctuation">}</span> renderItem<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> item <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>List<span class="token punctuation">.</span>Item key<span class="token operator">=</span><span class="token punctuation">{</span>item<span class="token punctuation">.</span>id<span class="token punctuation">}</span> title<span class="token operator">=</span><span class="token punctuation">{</span>item<span class="token punctuation">.</span>attributes<span class="token punctuation">.</span>title<span class="token punctuation">}</span> description<span class="token operator">=</span><span class="token punctuation">{</span>item<span class="token punctuation">.</span>attributes<span class="token punctuation">.</span>date<span class="token punctuation">}</span> onPress<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> navigation<span class="token punctuation">.</span><span class="token function">navigate</span><span class="token punctuation">(</span><span class="token string">'Editor'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">note</span><span class="token operator">:</span> item <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> refreshing<span class="token operator">=</span><span class="token punctuation">{</span>loading<span class="token punctuation">}</span> onRefresh<span class="token operator">=</span><span class="token punctuation">{</span>loadNotes<span class="token punctuation">}</span> style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'100%'</span><span class="token punctuation">,</span> <span class="token literal-property property">height</span><span class="token operator">:</span> <span class="token string">'100%'</span><span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Snackbar visible<span class="token operator">=</span><span class="token punctuation">{</span>error<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">}</span> onDismiss<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setError</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{</span>error<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>Snackbar<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>View<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>You first create the state variable <code class="language-text">notes</code> which will hold the notes when received from the Strapi backend. You use a <a href="https://reactnative.dev/docs/flatlist">FlatList</a> component to display the notes. This will render each note using the <a href="https://callstack.github.io/react-native-paper/list-item.html">List.Item</a> component from React Native Paper. The title of the item will be the title of the note, and the description will be the date of the note.</p><p>When the item in the list is clicked, the user will be taken to the <code class="language-text">Editor</code> screen (which you'll create in the next section).</p><p>The fetching of the notes will happen in the <code class="language-text">loadNotes</code> function. This function is called when the screen first opens, when the screen gains focus, and when the flat list is refreshed.</p><p>In the <code class="language-text">loadNotes</code> function, you send a request to <code class="language-text">http://<IP>:1337/api/notes</code>. Notice that to run the app on your phone, you need to use your machine's network IP. So, replace <code class="language-text"><IP></code> with your machine's IP.</p><p>This endpoint is Strapi's Endpoint for <a href="https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html#get-entries">fetching the entries</a> of a content type. You then set the <code class="language-text">notes</code> state variable to the data received from Strapi.</p><p>Next, you need to make changes to the <code class="language-text">App.js</code> file to show different screens.</p><p>Open <code class="language-text">App.js</code> and replace the content with the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> NavigationContainer <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@react-navigation/native'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> createNativeStackNavigator <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@react-navigation/native-stack'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> IconButton <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-paper'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> EditorScreen <span class="token keyword">from</span> <span class="token string">'./screens/EditorScreen'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> HomeScreen <span class="token keyword">from</span> <span class="token string">'./screens/HomeScreen'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> Stack <span class="token operator">=</span> <span class="token function">createNativeStackNavigator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>NavigationContainer<span class="token operator">></span> <span class="token operator"><</span>Stack<span class="token punctuation">.</span>Navigator<span class="token operator">></span> <span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Home"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>HomeScreen<span class="token punctuation">}</span> options<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>navigation<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token function-variable function">headerRight</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>IconButton icon<span class="token operator">=</span><span class="token string">'plus'</span> onPress<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> navigation<span class="token punctuation">.</span><span class="token function">navigate</span><span class="token punctuation">(</span><span class="token string">'Editor'</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Stack<span class="token punctuation">.</span>Navigator<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>NavigationContainer<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre></div><p>Notice that the <code class="language-text">Home</code> screen has a button at the top right that will take you to the <code class="language-text">Editor</code> screen.</p><p>Now, let's run the app. In your terminal, run the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>This will allow you to open the app on iOS or Android. You'll need the <a href="https://expo.dev/client">Expo Go</a> app on your phone. Then, on Android, open the app and scan the QR code in the terminal or the developer tool page to open the app. Alternatively, on iOS, you need to scan the QR code in your Camera app which will let you open the app in Expo Go.</p><p>When you open the app, you'll see an empty home screen.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/IMG_2484-2.PNG" class="kg-image" alt="How to Create a Notes App with Strapi v4 and React Native" loading="lazy" width="880" height="1904"/></figure><h2 id="create-editor-screen">Create Editor Screen</h2><p>Now, you'll create the editor screen which will show the user the editor with either the content filled (if editing an existing note) or an empty rich text editor.</p><p>Create <code class="language-text">screens/EditorScreen.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useLayoutEffect<span class="token punctuation">,</span> useRef<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> RichEditor<span class="token punctuation">,</span> RichToolbar<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-native-pell-rich-editor"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Keyboard<span class="token punctuation">,</span> KeyboardAvoidingView<span class="token punctuation">,</span> ScrollView<span class="token punctuation">,</span> View <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button<span class="token punctuation">,</span> Colors<span class="token punctuation">,</span> Snackbar<span class="token punctuation">,</span> Subheading<span class="token punctuation">,</span> TextInput <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-paper'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> axios <span class="token keyword">from</span> <span class="token string">'axios'</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">EditorScreen</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> route<span class="token punctuation">,</span> navigation <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> editor <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>title<span class="token punctuation">,</span> setTitle<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span>route<span class="token punctuation">.</span>params <span class="token operator">&&</span> route<span class="token punctuation">.</span>params<span class="token punctuation">.</span>note <span class="token operator">?</span> route<span class="token punctuation">.</span>params<span class="token punctuation">.</span>note<span class="token punctuation">.</span>attributes<span class="token punctuation">.</span>title <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>content<span class="token punctuation">,</span> setContent<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span>route<span class="token punctuation">.</span>params <span class="token operator">&&</span> route<span class="token punctuation">.</span>params<span class="token punctuation">.</span>note <span class="token operator">?</span> route<span class="token punctuation">.</span>params<span class="token punctuation">.</span>note<span class="token punctuation">.</span>attributes<span class="token punctuation">.</span>content <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>error<span class="token punctuation">,</span> setError<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span> <span class="token keyword">function</span> <span class="token function">saveNote</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> editor<span class="token punctuation">.</span>current<span class="token punctuation">.</span><span class="token function">blurContentEditor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//lose focus for editor and close keyboard</span> Keyboard<span class="token punctuation">.</span><span class="token function">dismiss</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> trimmedTitle <span class="token operator">=</span> title<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> trimmedContent <span class="token operator">=</span> content<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>trimmedTitle<span class="token punctuation">.</span>length <span class="token operator">||</span> <span class="token operator">!</span>trimmedContent<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setError</span><span class="token punctuation">(</span><span class="token string">'Please fill both title and content'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">axios</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">method</span><span class="token operator">:</span> route<span class="token punctuation">.</span>params <span class="token operator">&&</span> route<span class="token punctuation">.</span>params<span class="token punctuation">.</span>note <span class="token operator">?</span> <span class="token string">'PUT'</span> <span class="token operator">:</span> <span class="token string">'POST'</span><span class="token punctuation">,</span> <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'http://<IP>:1337/api/notes'</span> <span class="token operator">+</span> <span class="token punctuation">(</span>route<span class="token punctuation">.</span>params <span class="token operator">&&</span> route<span class="token punctuation">.</span>params<span class="token punctuation">.</span>note <span class="token operator">?</span> <span class="token string">'/'</span> <span class="token operator">+</span> route<span class="token punctuation">.</span>params<span class="token punctuation">.</span>note<span class="token punctuation">.</span>id <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> title<span class="token punctuation">,</span> content<span class="token punctuation">,</span> <span class="token literal-property property">date</span><span class="token operator">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//redirect back to home screen</span> navigation<span class="token punctuation">.</span><span class="token function">goBack</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setError</span><span class="token punctuation">(</span><span class="token string">'An error occurred, please try again later'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">deleteNote</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> axios<span class="token punctuation">.</span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token string">'http://<IP>:1337/api/notes/'</span> <span class="token operator">+</span> route<span class="token punctuation">.</span>params<span class="token punctuation">.</span>note<span class="token punctuation">.</span>id<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//redirect back to home screen</span> navigation<span class="token punctuation">.</span><span class="token function">goBack</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setError</span><span class="token punctuation">(</span><span class="token string">'An error occurred, please try again later.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">useLayoutEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> navigation<span class="token punctuation">.</span><span class="token function">setOptions</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">headerTitle</span><span class="token operator">:</span> content<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span> <span class="token operator">?</span> <span class="token string">'New Note'</span> <span class="token operator">:</span> <span class="token string">'Edit Note'</span><span class="token punctuation">,</span> <span class="token literal-property property">headerRight</span><span class="token operator">:</span> route<span class="token punctuation">.</span>params <span class="token operator">&&</span> route<span class="token punctuation">.</span>params<span class="token punctuation">.</span>note <span class="token operator">?</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>Button color<span class="token operator">=</span><span class="token punctuation">{</span>Colors<span class="token punctuation">.</span>redA100<span class="token punctuation">}</span> onPress<span class="token operator">=</span><span class="token punctuation">{</span>deleteNote<span class="token punctuation">}</span><span class="token operator">></span>Delete<span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token operator"><</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>View style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token literal-property property">margin</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token literal-property property">flex</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">justifyContent</span><span class="token operator">:</span> <span class="token string">'space-between'</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>TextInput label<span class="token operator">=</span><span class="token string">"Title"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>title<span class="token punctuation">}</span> onChangeText<span class="token operator">=</span><span class="token punctuation">{</span>setTitle<span class="token punctuation">}</span> mode<span class="token operator">=</span><span class="token string">"outlined"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Subheading<span class="token operator">></span>Content<span class="token operator"><</span><span class="token operator">/</span>Subheading<span class="token operator">></span> <span class="token operator"><</span>RichToolbar editor<span class="token operator">=</span><span class="token punctuation">{</span>editor<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>ScrollView keyboardDismissMode<span class="token operator">=</span><span class="token string">'onDrag'</span><span class="token operator">></span> <span class="token operator"><</span>KeyboardAvoidingView behavior<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">"position"</span><span class="token punctuation">}</span> style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">flex</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> keyboardVerticalOffset<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">250</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>RichEditor style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">flex</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">}</span> ref<span class="token operator">=</span><span class="token punctuation">{</span>editor<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span>setContent<span class="token punctuation">}</span> initialContentHTML<span class="token operator">=</span><span class="token punctuation">{</span>content<span class="token punctuation">}</span> placeholder<span class="token operator">=</span><span class="token string">'Start typing...'</span> useContainer <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Button onPress<span class="token operator">=</span><span class="token punctuation">{</span>saveNote<span class="token punctuation">}</span> mode<span class="token operator">=</span><span class="token string">"contained"</span> style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token literal-property property">marginTop</span><span class="token operator">:</span> <span class="token number">20</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> Save <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>KeyboardAvoidingView<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>ScrollView<span class="token operator">></span> <span class="token operator"><</span>Snackbar visible<span class="token operator">=</span><span class="token punctuation">{</span>error<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">}</span> onDismiss<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setError</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{</span>error<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>Snackbar<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>View<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>In this code snippet, you create a <code class="language-text">editor</code> ref variable for the Rich text editor. This is necessary for the library you're using. You also create a <code class="language-text">title</code> and <code class="language-text">content</code> state variables. These will be used to store the input values and will have as initial values the note's title and content if it exists.</p><p>On the screen, you show a rich text editor with a toolbar to add advanced text editing. You also add a Save button and a Delete button for existing notes.</p><h3 id="save-a-note">Save a Note</h3><p>When the Save button is clicked, you check if the note exists or is new. If the note already exists, then, a <code class="language-text">PUT</code> request is sent to <code class="language-text">http://<IP>:1337/api/notes/<note_id></code>, where <code class="language-text"><IP></code> is your machine's IP and <code class="language-text"><note_id></code> is the current note's ID. This Strapi endpoint is used to <a href="https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html#update-an-entry">update an entry</a> in a collection.</p><p>Alternatively, if the note is new, a <code class="language-text">POST</code> request is sent to <code class="language-text">http://<IP>:1337/api/notes</code>, where <code class="language-text"><IP></code> is your machine's IP. This Strapi endpoint is used to <a href="https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html#create-an-entry">create an entry</a>.</p><p>Both requests accept in the body of the request a <code class="language-text">data</code> parameter with the entry's data. You pass the title, content, and current date.</p><h3 id="delete-a-note">Delete a Note</h3><p>When the Delete Button is clicked, a <code class="language-text">DELETE</code> request is sent to <code class="language-text">http://<IP>:1337/api/notes/<note_id></code>, where <code class="language-text"><IP></code> is your machine's IP and <code class="language-text"><note_id></code> is the ID of the note to delete. Remember, this is only available if the note exists.</p><p>After the note is saved or deleted, you take the user back to the home screen.</p><p>Next, you need to add the new screen to <code class="language-text">App.js</code>. Add it after the <code class="language-text">Home</code> screen:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Editor"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>EditorScreen<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>That's all, now run the app if it's not running. Try first clicking on the <code class="language-text">+</code> button at the top right of the home screen. You'll see a rich text editor with a toolbar and a Save button.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/IMG_2485-2.PNG" class="kg-image" alt="How to Create a Notes App with Strapi v4 and React Native" loading="lazy" width="880" height="1904"/></figure><h3 id="add-a-note">Add a Note</h3><p>Try entering any content in both title and content fields. Once you're done, click Save. You'll be taken back to the home screen where you can see the new item you added.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/IMG_2472-2.PNG" class="kg-image" alt="How to Create a Notes App with Strapi v4 and React Native" loading="lazy" width="880" height="1904"/></figure><h2 id="edit-a-note">Edit a Note</h2><p>Now, click on a note and edit its content, then click Save. If you click on that note again, you'll see that the content has been edited successfully.</p><h2 id="delete-a-note-1">Delete a Note</h2><p>If you click on a note from the home screen, you'll notice a delete button at the top right of the screen.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/03/IMG_2471-2.PNG" class="kg-image" alt="How to Create a Notes App with Strapi v4 and React Native" loading="lazy" width="880" height="1904"/></figure><p>Click on the delete button and you'll be taken back to the home screen where you can see your note does not exist anymore.</p><h2 id="conclusion">Conclusion</h2><p>This simple note app showcases how you can connect a React Native app to Strapi. Strapi makes it simple to add CMS capabilities to apps using React Native. Using a CMS like Strapi to easily manage the notes on your app allows you to also manage the notes on different platforms like on the web.</p>]]></content:encoded></item><item><title><![CDATA[What is Intuitive Design and Why is It Important?]]></title><description><![CDATA[In this article, you'll learn more about what intuitive design is, why it's important for your websites and apps.]]></description><link>https://blog.shahednasser.com/what-is-intuitive-design-and-why-is-it-important/</link><guid isPermaLink="false">Ghost__Post__61f02d6ae37d1cfea32a7ee4</guid><category><![CDATA[Design]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 01 Feb 2022 11:56:45 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/b83e23d21219ae6d2d1ca15a83144f5f/What-is-Intuitive-Design-and-Why-is-It-Important.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/b83e23d21219ae6d2d1ca15a83144f5f/What-is-Intuitive-Design-and-Why-is-It-Important.jpg" alt="What is Intuitive Design and Why is It Important?"/><p>Think of the last time you used an app or a website. Were you able to right away do what you want without anyone teaching you how to do it? Were you able to find what you need without anyone pointing you in the right direction? If your answers are yes, then you probably experienced an app with a good, intuitive design.</p><p>People tend to get used to doing things a certain way. As they use all kinds of apps and websites throughout their day, they get familiar with how something is supposed to be done.</p><p>If I want to download this file, I should click the download button. If I want to open my cart in an online store, I know I'll find an icon at the top right (or left, depending on the language direction) that either looks like a bag or a shopping cart. If I want to go to my profile, I should click on my avatar image. This uniform experience between different platforms makes it easier for people to navigate the web efficiently and stress-free.</p><p>This familiar experience that users look for in different platforms relies on the platform's intuitive design. An intuitive design is a design that makes sure when people use this platform, they can instantly figure out how to perform certain actions.</p><p>In this article, you'll learn more about what intuitive design is, why it's important for your websites and apps.</p><h2 id="what-is-intuitive-design">What is Intuitive Design </h2><p>Technically speaking, there's no official definition of Intuitive Design. Just like what it means, it's a concept that has been realized with experience and time.</p><p>If you create an app, your primary goal is that people would want to use it. Developers or even business people tend to think that this means adding more features or having a pretty design. </p><p>Although the features you provide and the design of your website are important, if people find it hard to use then they're not going to use it. This is especially true in this time of age where almost every app out there has an alternative. Don't like Facebook? You can go for Twitter. Don't like Whatsapp? You can go for Telegram. Although these apps might not be similar in all the features they provide, from a user's perspective they all allow the user to do the same thing, but one allows them to do it better than the other.</p><p>But what makes a website or an app hard to use? Simply put, if I, as a user, have to take a long time to figure out how to do or find something, then this app is hard to use.</p><p>Ok, but how do I expect users to just <em>know</em> how to do something? The simplest way to do that is to provide them with a familiar design. The familiarity in question can either be from their experience on the web or their experience in real life.</p><p>Users spend most of their day surfing the web. Whether they're shopping online, messaging their friends, watching videos, or attending an online meeting. The longer they use an app, the more they become experts at it. They start understanding where to find what they need in that app.</p><p>One aspect of intuitive design is taking advantage of that and providing a design that makes the user right at home. The design in question can be a lot of different elements. It can be colors. For example, if a user sees a message with green color, then their operation went successfully. If it's red, then something went wrong. Similarly, if they see a button with more vibrant or apparent color, then they're going to assume this is the "Yes" button. Messing up these colors can cause a misunderstanding and can lead to wrong actions.</p><p>But that's not just it. Intuitive design is also bringing elements from the real world into your user's experience when fitting. A simple example of this would be the cart icon in online stores. Why don't we just use a TV icon for a shopping cart? The answer to this is, "duh, it's a shopping cart!"</p><p>Being able to recognize what to do because you're familiar with it in your real-life experiences is also what contributes to an intuitive design. This is especially essential when you're creating an app or a feature that isn't necessarily widely available or used. Figuring out how to make the user's experience of this app as easy as possible isn't easy in itself.</p><p>You should, then, take a good time to try and bring this feature into life. Try to relate it to our everyday life and how it would make users understand right off the bat that "oh since this is a shopping cart it must be where all my items are".</p><h2 id="why-is-intuitive-design-important">Why is Intuitive Design Important?</h2><p>By providing an experience your user is used to, your user will generally be able to do the things they wanted to do with your website and app successfully and quickly. Not only does this save them time and allow them to be more efficient, but this makes them feel like they've been using your platform all along even if it's their first time.</p><p>This sense of familiarity creates a connection between your product and your user. It'll make them come back to or keep using your platform more and more. </p><p>If you look online, there are countless design statistics that prove how bad design can lead to a bad user experience, and ultimately to users not using the platform at all. Although the bad design and bad user experience aren't necessarily only caused by no intuitive design, it's definitely a contributor to it.</p><p>To ensure that your users love what you're offering them, and to ensure that they come back time and again to use your platform, you should take the time to build and rebuild your design to how they're familiar with using it.</p><h2 id="conclusion">Conclusion</h2><p>As technical people, we tend to forget that most people aren't tech-savvy. Most people are confused by how they're supposed to do the simplest of actions that may seem easy to us.</p><p>So, it's important that when you create a design you ensure that it incorporates the user's daily experiences into it. The includes real and virtual experiences.</p><p>By creating an intuitive design that is born from people's everyday life, you'll be creating a great experience for your users who will return to your website or app again and again.</p>]]></content:encoded></item><item><title><![CDATA[How to Internationalize (i18n) a React App with Transifex Native]]></title><description><![CDATA[In this article, you’ll learn how to internationalize a React app using Transifex Native.]]></description><link>https://blog.shahednasser.com/how-to-internationalize-i18n-a-react-app-with-transifex-native/</link><guid isPermaLink="false">Ghost__Post__61efd82ce37d1cfea32a7e97</guid><category><![CDATA[Reviews]]></category><category><![CDATA[React]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 26 Jan 2022 08:12:44 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/6862735adb4197b52f0aae64539e1079/How-to-Internationalize--i18n--a-React-App-with-Transifex-Native.jpg" medium="image"/><content:encoded><</code> <a href="https://docs.transifex.com/javascript-sdk/localize-react-applications#languagepicker-component">component</a> from the same SDK that provides the entire UI and functionality ready for you. However, you will not have the ability to customize the UI.</p><p>Open <code class="language-text">src/components/Navigation.js</code> and add the following imports at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import { tx } from '@transifex/native'; import { useLanguages } from '@transifex/react'; </code></pre></div><p>Then, inside the <code class="language-text">Navigation</code> function create a new <code class="language-text">languages</code> variable:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">const languages = useLanguages(); </code></pre></div><p>Then, replace the elements nested inside <code class="language-text">NavDropdown</code> with the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">{languages.map(({code, name}) => ( <NavDropdown.Item key={code} href="#" onClick={() => tx.setCurrentLocale(code)}>{name}</NavDropdown.Item> ))} </code></pre></div><p>This will loop over the <code class="language-text">languages</code> variable. Each <code class="language-text">language</code> inside it will have <code class="language-text">code</code> and <code class="language-text">name</code> attributes. You use that to display each language as a dropdown item in the navigation bar. When the item is clicked, the language will be changed to the clicked language using <code class="language-text">tx.setCurrentLocale</code>, which accepts the language code (or locale) as a parameter.</p><p>If you open your website now, you should see the languages when you click on the Languages dropdown.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-20-at-11.31.39-AM.png" class="kg-image" alt="How to Internationalize (i18n) a React App with Transifex Native" loading="lazy" width="378" height="316"/></figure><p>Try clicking on the second language, which in my case is Arabic. You’ll see that all the strings will be translated as you translated them in your Transifex Native project dashboard.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-20-at-11.33.37-AM.png" class="kg-image" alt="How to Internationalize (i18n) a React App with Transifex Native" loading="lazy" width="2000" height="230" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-20-at-11.33.37-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-20-at-11.33.37-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-20-at-11.33.37-AM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2022/01/Screen-Shot-2022-01-20-at-11.33.37-AM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><h2 id="translating-more-text">Translating More Text</h2><p>Let’s now translate the “Language” string in the Navigation component.</p><p>In <code class="language-text">src/components/Navigation.js</code> file add the import for <code class="language-text">T</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import { T, useLanguages } from '@transifex/react'; </code></pre></div><p>Then, change the <code class="language-text">title</code> prop of <code class="language-text">NavDropdown</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">title={<T _str="Language" />} </code></pre></div><p>The <code class="language-text">title</code> prop can accept a component as a value.</p><p>You’ll need to push the new string to the Transifex Native project so run the <code class="language-text">push-translation</code> command again:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm run push-translation </code></pre></div><p>This will push all new strings and skip already-created strings. If you open your project dashboard now you should see a new string “Language” added there.</p><p>Go ahead and translate the string, then run the website again. You might see that the “Language” string isn’t translated right away when you switch languages. That’s because Transifex Native caches your translations.</p><p>To invalidate the cache, you can use the <code class="language-text">invalidate</code> command of the CLI tool.</p><p>In <code class="language-text">package.json</code> add the new script <code class="language-text">refresh-translation</code> and make changes to the <code class="language-text">start</code> script so that the translations are refreshed whenever the server for your website is started:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">"scripts": { "start": "npm run refresh-translation && react-scripts start", ..., "refresh-translation": "txjs-cli invalidate --token=<TOKEN> --secret=<SECRET>" }, </code></pre></div><p>Just like before, make sure to replace <code class="language-text"><TOKEN></code> and <code class="language-text"><SECRET></code> with your credentials.</p><p>Now, run the <code class="language-text">start</code> command again or run the <code class="language-text">refresh-translation</code>command on its own. The “Language” string should now be translated when you switch languages.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-19-at-1.04.05-PM-1.png" class="kg-image" alt="How to Internationalize (i18n) a React App with Transifex Native" loading="lazy" width="2000" height="252" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-19-at-1.04.05-PM-1.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-19-at-1.04.05-PM-1.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-19-at-1.04.05-PM-1.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2022/01/Screen-Shot-2022-01-19-at-1.04.05-PM-1.png 2400w" sizes="(min-width: 720px) 720px"/></figure><h1 id="changing-layout">Changing Layout</h1><p>The next part of internationalization is making sure that the layout conforms with the selected language’s directionality. As Arabic is a right-to-left (RTL) language, the layout needs to be flipped when the Arabic language is chosen.</p><p>The Transifex Native React SDK has a <code class="language-text">useLocale</code> hook that you can use to retrieve the current chosen locale. We’ll use that to change the document direction and make any necessary changes based on the current language.</p><p>In <code class="language-text">src/App.js</code> add imports at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import React, { useEffect } from 'react'; import { useLocale } from '@transifex/react'; </code></pre></div><p>Then, inside the <code class="language-text">App</code> function, add the following before the <code class="language-text">return</code>statement:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">const locale = useLocale(); useEffect(() => { if (locale) { document.body.style.direction = locale === 'en' ? 'ltr' : 'rtl'; } }, [locale]); </code></pre></div><p>You first retrieve the locale using <code class="language-text">useLocale</code>. Then, whenever <code class="language-text">locale</code> is changed, you change the <code class="language-text">direction</code> style property of the <code class="language-text">body</code> of the page based on the locale.</p><p>Next, in <code class="language-text">src/components/Navbar.js</code> add the necessary import for <code class="language-text">useLocale</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import { T, useLanguages, useLocale } from '@transifex/react'; </code></pre></div><p>Then, create the <code class="language-text">locale</code> variable inside the <code class="language-text">Navigation</code> function:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">const locale = useLocale(); </code></pre></div><p>Finally, change the <code class="language-text">className</code> prop of the <code class="language-text">Nav</code> element to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">className={!locale || locale === 'en' ? "ms-auto" : "me-auto"} </code></pre></div><p>This will make sure that when the language is English the “Language” dropdown will appear at the right, otherwise, it will appear on the left.</p><p>Now, open the website and switch to an RTL language. You should see that the layout has changed.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-19-at-1.06.24-PM.png" class="kg-image" alt="How to Internationalize (i18n) a React App with Transifex Native" loading="lazy" width="2000" height="329" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-19-at-1.06.24-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-19-at-1.06.24-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-19-at-1.06.24-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2022/01/Screen-Shot-2022-01-19-at-1.06.24-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>If you try to switch back to English, the layout will go back to the way it was.</p><h1 id="benefits-of-transifex-native-react-sdk">Benefits of Transifex Native React SDK</h1><p>If you went through the previous i18next tutorial, or you already know how i18next works, and you went through this tutorial, you can easily spot all the benefits of the Transifex Native React SDK.</p><p>The main benefit of using Transifex Native is that the translations are not part of your codebase. For bigger projects or projects that require translators that aren’t tech-savvy, this makes it much easier to translate a website, as the translation can all happen from the dashboard. Developers can then just focus on developing the website as necessary.</p><p>This is also very beneficial for projects that include multiple environments. If you have a website, an iOS app, and an Android app, it’s a hassle to internationalize all these different projects as they each have a different way of translating string resources. As Transifex has <a href="https://docs.transifex.com/getting-started-with-native/getting-started-with-transifex-native">SDKs for all these types of projects</a>, and as it also has <a href="https://transifex.github.io/openapi/index.html">REST APIs</a> that allow you to access your project resources from basically anywhere, all you need is to translate these strings on the Transifex Native project dashboard and any component of your application can have access to them.</p><p>Another benefit of using Transifex’s SDKs is how easy it is to retrieve languages and currently selected locales. When I used i18next in the previous tutorial, retrieving the current locale had to be done through <a href="https://reactjs.org/docs/context.html">React Context</a>. This concept can seem complex to some, so to be able to easily retrieve the current locale is also a nice plus.</p><p>The Transifex Native React SDK adds an easy interface and components that you can use in your code to remove all the hassles that might come with internationalization. This is a big plus for the developer experience.</p><h1 id="conclusion">Conclusion</h1><p>Transifex is the perfect platform for internationalizing a lot of types of projects, especially React apps. With Transifex Native, you can use the React SDK to add strings to be translated, get languages, get current locale, and more. You can then easily translate the strings from the dashboard and access them whenever.</p><p>I found Transifex Native very easy to use as a developer. Its process allows you to stay efficient and focused on the programming part. When it comes to localization and translating your content, you’ll most likely need the help of other team members, and there’s a chance they won’t know how to do it through editing the source code. <a href="https://www.transifex.com/blog/2021/react-i18n-data-backed-benefits-of-transifex-native/">This is something that you can solve with Transifex</a>. You can also <a href="https://docs.transifex.com/localization-tips-workflows/crowdsourcing-translations">crowdsource</a> your translation if you have an open-source project and need the help of the community.</p><p>Be sure to check out <a href="https://docs.transifex.com/javascript-sdk/localize-react-applications">Transifex’s React SDK documentation</a> to see all the functionalities it provides and see all the cool things you can do with this SDK and platform as a whole.</p>]]></content:encoded></item><item><title><![CDATA[How to Add Authentication with Google Authenticator in Node.js]]></title><description><![CDATA[In this tutorial, you'll learn how to add authentication with authenticator apps like Google Authenticator in Node.js.]]></description><link>https://blog.shahednasser.com/how-to-add-authentication-with-google-authenticator-in-node-js/</link><guid isPermaLink="false">Ghost__Post__61eaec366e875c05c40940de</guid><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 25 Jan 2022 10:12:09 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/1e84d0756490377474177d14f768f442/How-to-Add-Authentication-with-Google-Authenticator-in-Node.js-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/1e84d0756490377474177d14f768f442/How-to-Add-Authentication-with-Google-Authenticator-in-Node.js-2.jpg" alt="How to Add Authentication with Google Authenticator in Node.js"/><p>2-Factor Authentication (2FA) adds an extra level of security to your website or app. Using 2FA, the user can rest at ease that just because someone has their password doesn't mean that they can access their account.</p><p>One form of 2FA is using authenticator apps like Google's <a href="https://en.wikipedia.org/wiki/Google_Authenticator">Authenticator</a>. What happens is that after your user registers or enables 2FA on their account, you generate a secret and create a QR code based on that secret. Then, the user can scan that QR code with their authenticator app. </p><p>After the user scans the QR code, they'll start getting time-based one-time passwords (TOTP) in the app. A 6-digit code will be shown and changed every 30 seconds. When the user needs to log in, they'll be asked to enter the code they see in the app. If the code is correct, they're allowed to log in. Otherwise, the login fails.</p><p>In this tutorial, you'll learn how to implement this process in Node.js. You'll create a simple website that requires users to enable authentication with an authenticator app when they register and then to enter the code every time they log in. This doesn't only work with Google's Authenticator, but also with Microsoft's Authenticator, or any other TOTP authentication apps.</p><p>For simplicity, this tutorial only focuses on authentication with the authenticator app. So, a lot of the necessary details related to 2FA, validation, and security might be omitted from the tutorial.</p><p>You can find the code for this tutorial in <a href="https://github.com/shahednasser/node-2fa-tutorial">this GitHub repository</a>.</p><h2 id="prerequisites">Prerequisites</h2><p>You need <a href="https://nodejs.org">Node.js</a> installed on your machine to be able to follow along with this tutorial.</p><h2 id="project-setup">Project Setup</h2><p>Start by creating a directory for our project and changing to it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> 2fa-tutorial <span class="token builtin class-name">cd</span> 2fa-tutorial</code></pre></div><p>Then, initialize the project with NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> init -y</code></pre></div><p>The <code class="language-text">-y</code> option will fill the fields of <code class="language-text">package.json</code> with default values.</p><p>Next, install the dependencies that you'll use for this tutorial:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i express ejs body-parser express-session express-jwt jsonwebtoken sqlite3 otplib qrcode nodemon</code></pre></div><p>Here's what each dependency is for:</p><ol><li><code class="language-text">express</code>: To create a server</li><li><code class="language-text">ejs</code>: View engine to be used to create pages</li><li><code class="language-text">body-parser</code>: To parse body parameters from the request</li><li><code class="language-text">express-session</code>: Manage session in the server</li><li><code class="language-text">express-jwt</code> and <code class="language-text">jsonwebtoken</code>: Create JSON Web Token (JWT) and add middleware to ensure that a user is authenticated</li><li><code class="language-text">sqlite3</code>: To interact with an SQLite database</li><li><code class="language-text">otplib</code>: To generate the secret which will be used to add 2FA with the authenticator app</li><li><code class="language-text">qrcode</code>: To generate the QRCode that should be scanned by the authenticator app</li><li><code class="language-text">nodemon</code>: To restart the server whenever there are changes</li></ol><p>Out of all these dependencies, the important ones for 2FA are <code class="language-text">otplib</code> and <code class="language-text">qrcode</code>. The rest are more related to setting up the server and website.</p><h2 id="create-server">Create Server</h2><p>Create <code class="language-text">index.js</code> in the root directory with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'express'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> sqlite3 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'sqlite3'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> session <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'express-session'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> authenticator <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'otplib'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> QRCode <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'qrcode'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> jwt <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'jsonwebtoken'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> expressJWT <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'express-jwt'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> bodyParser <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'body-parser'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> port <span class="token operator">=</span> <span class="token number">3000</span> app<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">'view engine'</span><span class="token punctuation">,</span> <span class="token string">'ejs'</span><span class="token punctuation">)</span> app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token function">session</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">secret</span><span class="token operator">:</span> <span class="token string">'supersecret'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span> app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>bodyParser<span class="token punctuation">.</span><span class="token function">urlencoded</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">extended</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">//create database with tables if it doesn't exist</span> <span class="token keyword">const</span> db <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">sqlite3<span class="token punctuation">.</span>Database</span><span class="token punctuation">(</span><span class="token string">'db.sqlite'</span><span class="token punctuation">)</span> db<span class="token punctuation">.</span><span class="token function">serialize</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> db<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token string">'CREATE TABLE IF NOT EXISTS `users` (`user_id` INTEGER PRIMARY KEY AUTOINCREMENT, `email` VARCHAR(255) NOT NULL, `secret` varchar(255) NOT NULL)'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> db<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span> app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span>port<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">2FA Node app listening at http://localhost:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>port<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>This imports all the dependencies that you'll use throughout the tutorial. Then, you create a server with Express and create an SQLite database with a <code class="language-text">users</code> table if they don't exist. The <code class="language-text">users</code> table, for simplicity, will only have the columns <code class="language-text">user_id</code>, <code class="language-text">email</code> and <code class="language-text">secret</code>.</p><h2 id="create-sign-up-page">Create Sign Up Page</h2><p>The home page of the website will be the signup page.</p><p>In <code class="language-text">index.js</code> add the route for <code class="language-text">/</code> as follows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token string">'signup.ejs'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>This will only render the EJS view <code class="language-text">signup.ejs</code> which you'll create next.</p><p>Create <code class="language-text">views/signup.ejs</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>IE=edge<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Sign Up<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">integrity</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3<span class="token punctuation">"</span></span> <span class="token attr-name">crossorigin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>anonymous<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>container mx-auto mt-4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Sign Up<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>form</span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/sign-up<span class="token punctuation">"</span></span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mb-3<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form-label<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Email<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn-primary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Sign Up<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>form</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mt-4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Have an account? <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/login<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Login<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre></div><p>This will show a form with only an email input and a submit button. After the user enters their email and clicks on submit, their account will be redirected and will be redirected to scan the QR code.</p><p>Back in <code class="language-text">index.js</code>, create the <code class="language-text">POST</code> route to handle the registration:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">'/sign-up'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> email <span class="token operator">=</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>email<span class="token punctuation">,</span> secret <span class="token operator">=</span> authenticator<span class="token punctuation">.</span><span class="token function">generateSecret</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> db <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">sqlite3<span class="token punctuation">.</span>Database</span><span class="token punctuation">(</span><span class="token string">'db.sqlite'</span><span class="token punctuation">)</span> db<span class="token punctuation">.</span><span class="token function">serialize</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> db<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token string">'INSERT INTO `users`(`email`, `secret`) VALUES (?, ?)'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>email<span class="token punctuation">,</span> secret<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> err <span class="token punctuation">}</span> <span class="token comment">//generate qr and put it in session</span> QRCode<span class="token punctuation">.</span><span class="token function">toDataURL</span><span class="token punctuation">(</span>authenticator<span class="token punctuation">.</span><span class="token function">keyuri</span><span class="token punctuation">(</span>email<span class="token punctuation">,</span> <span class="token string">'2FA Node App'</span><span class="token punctuation">,</span> secret<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err<span class="token punctuation">,</span> url</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> err <span class="token punctuation">}</span> req<span class="token punctuation">.</span>session<span class="token punctuation">.</span>qr <span class="token operator">=</span> url req<span class="token punctuation">.</span>session<span class="token punctuation">.</span>email <span class="token operator">=</span> email res<span class="token punctuation">.</span><span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string">'/sign-up-2fa'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>You first retrieve the email from the body and you create a secret using <code class="language-text">authenticator.generateSecret</code>. <code class="language-text">authenticator</code> is from the <code class="language-text">otplib</code> library. <code class="language-text">generateSecret</code> generates a base32 encoded hex secret that will be used to add your app into an authenticator app like Google Authenticator.</p><p>Then, you connect to the database and insert a new user with the email and secret. If all goes well, you generate a QRCode from <code class="language-text">qrcode</code> library. The QRCode content should be a <a href="https://github.com/google/google-authenticator/wiki/Key-Uri-Format">Key Uri</a> of the following format:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">otpauth://{type}/{app}:{accountName}?secret={secret}{query}</code></pre></div><p>Where <code class="language-text">{type}</code> is either <code class="language-text">totp</code> for TOTP or <code class="language-text">hotp</code> for HMAC-based one-time password (HOTP). For this tutorial, we're going with the default type for <code class="language-text">authenticator</code> in <code class="language-text">otplib</code> which is <code class="language-text">totp</code>.</p><p><code class="language-text">{app}</code> is the name of the app this 2FA is for. It will appear in the user's app after they scan the code. <code class="language-text">{accountName}</code> is their email in the app.</p><p><code class="language-text">{secret}</code> is the secret you generated earlier. You can also pass additional query parameters in the place of <code class="language-text">{query}</code> to customize the authentication. For example, you can change the number of digits of the TOTP codes from 6 to 8 using the query parameter <code class="language-text">&digits=8</code>.</p><p><code class="language-text">authenticator</code> has the method <code class="language-text">keyuri</code> which accepts an email (<code class="language-text">accountName</code>), the app's name (<code class="language-text">app</code>), and the secret (<code class="language-text">secret</code>) as parameters. You can, instead, pass an object of options, which will allow you to add customizations like the <code class="language-text">digits</code> query parameter.</p><p>The <code class="language-text">qrcode</code> library has the method <code class="language-text">toDataURL</code>. You'll use that to get the Data URL of the QRCode image and store it in the session to view it on the next page. You'll also set the email in the session for access on the next page.</p><p>If everything is successful, the user will be redirected to <code class="language-text">sign-up-2fa</code> where they add authentication with their authenticator app.</p><h2 id="create-add-authentication-page">Create Add Authentication Page</h2><p>In <code class="language-text">index.js</code>, add the new route <code class="language-text">sign-up-2fa</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/sign-up-2fa'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>req<span class="token punctuation">.</span>session<span class="token punctuation">.</span>qr<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token string">'signup-2fa.ejs'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">qr</span><span class="token operator">:</span> req<span class="token punctuation">.</span>session<span class="token punctuation">.</span>qr <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>If <code class="language-text">qr</code> isn't in the session, then you redirect the user to the home page. Otherwise, you render the <code class="language-text">signup-2fa.ejs</code> view passing it the QRCode data URL.</p><p>Create <code class="language-text">views/signup-2fa.ejs</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>IE=edge<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Sign Up - Set 2FA<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">integrity</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3<span class="token punctuation">"</span></span> <span class="token attr-name">crossorigin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>anonymous<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>container mx-auto mt-4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Sign Up - Set 2FA<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>form</span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/sign-up-2fa<span class="token punctuation">"</span></span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>Scan the QR Code in the Authenticator app then enter the code that you see in the app in the text field and click Submit.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><%= qr %><span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>img-fluid<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mb-3<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>code<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form-label<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>2FA Code<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>code<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>code<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn-primary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Submit<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>form</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre></div><p>This will show the QRCode with input to enter the code after the user scans the QRCode. This is just to verify that the user actually scanned the QRCode and now can log in using the authenticator app.</p><p>Now, you'll add the <code class="language-text">/sign-up-2fa</code> <code class="language-text">POST</code> route in <code class="language-text">index.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">'/sign-up-2fa'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>req<span class="token punctuation">.</span>session<span class="token punctuation">.</span>email<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> email <span class="token operator">=</span> req<span class="token punctuation">.</span>session<span class="token punctuation">.</span>email<span class="token punctuation">,</span> code <span class="token operator">=</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>code <span class="token keyword">return</span> <span class="token function">verifyLogin</span><span class="token punctuation">(</span>email<span class="token punctuation">,</span> code<span class="token punctuation">,</span> req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> <span class="token string">'/sign-up-2fa'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>This will retrieve the user's email and code from the session and request body respectively. Then, it will call the <code class="language-text">verifyLogin</code> function which you'll create next:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">verifyLogin</span> <span class="token punctuation">(</span><span class="token parameter">email<span class="token punctuation">,</span> code<span class="token punctuation">,</span> req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> failUrl</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//load user by email</span> <span class="token keyword">const</span> db <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">sqlite3<span class="token punctuation">.</span>Database</span><span class="token punctuation">(</span><span class="token string">'db.sqlite'</span><span class="token punctuation">)</span> db<span class="token punctuation">.</span><span class="token function">serialize</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> db<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'SELECT secret FROM users WHERE email = ?'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>email<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err<span class="token punctuation">,</span> row</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> err <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>row<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>authenticator<span class="token punctuation">.</span><span class="token function">check</span><span class="token punctuation">(</span>code<span class="token punctuation">,</span> row<span class="token punctuation">.</span>secret<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//redirect back</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">redirect</span><span class="token punctuation">(</span>failUrl<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">//correct, add jwt to session</span> req<span class="token punctuation">.</span>session<span class="token punctuation">.</span>qr <span class="token operator">=</span> <span class="token keyword">null</span> req<span class="token punctuation">.</span>session<span class="token punctuation">.</span>email <span class="token operator">=</span> <span class="token keyword">null</span> req<span class="token punctuation">.</span>session<span class="token punctuation">.</span>token <span class="token operator">=</span> jwt<span class="token punctuation">.</span><span class="token function">sign</span><span class="token punctuation">(</span>email<span class="token punctuation">,</span> <span class="token string">'supersecret'</span><span class="token punctuation">)</span> <span class="token comment">//redirect to "private" page</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string">'/private'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>This function, first, retrieves the user by their email. Then, the code is validated with the secret in the database using <code class="language-text">authenticator.check</code> method. This method takes the code as the first parameter and the secret as the second parameter. It returns a boolean value.</p><p>If the <code class="language-text">check</code> method returns true, it means that you can authenticate the user. You set the <code class="language-text">token</code> in the session to a JWT created by the <code class="language-text">jwt</code> library. Then, you redirect the user to the <code class="language-text">private</code> page that you'll create later.</p><h2 id="create-log-in-page">Create Log In Page</h2><p>Now you'll create the login page. This page will allow the user to enter their email and the code from the app to log in.</p><p>In <code class="language-text">index.js</code> add the <code class="language-text">/login</code> route:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/login'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token string">'login.ejs'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>This will just render the <code class="language-text">login.ejs</code> view.</p><p>Create <code class="language-text">views/login.ejs</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>IE=edge<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Log In<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">integrity</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3<span class="token punctuation">"</span></span> <span class="token attr-name">crossorigin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>anonymous<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>container mx-auto mt-4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Log In<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>form</span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/login<span class="token punctuation">"</span></span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mb-3<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form-label<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Email<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mb-3<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>code<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form-label<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Code<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>code<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>code<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>code<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn-primary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Log In<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>form</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mt-4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Don't have an account? <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Sign Up<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre></div><p>As mentioned, this page shows a form with 2 inputs: Email and Code. This form then sends the form data to the <code class="language-text">/login</code> <code class="language-text">POST</code> route.</p><p>In <code class="language-text">index.js</code> add the <code class="language-text">POST</code> route for <code class="language-text">login</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">'/login'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//verify login</span> <span class="token keyword">const</span> email <span class="token operator">=</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>email<span class="token punctuation">,</span> code <span class="token operator">=</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>code <span class="token keyword">return</span> <span class="token function">verifyLogin</span><span class="token punctuation">(</span>email<span class="token punctuation">,</span> code<span class="token punctuation">,</span> req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> <span class="token string">'/login'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>This function has similar functionality as the <code class="language-text">sign-up-2fa</code>. It retrieves the email and code from the body parameters then calls <code class="language-text">verifyLogin</code> to either log in the user or redirect them back to the form.</p><h2 id="create-private-page">Create Private Page</h2><p>Now, you'll create a private page, which is only accessible by logged-in users.</p><p>In <code class="language-text">index.js</code> add the route <code class="language-text">private</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> jwtMiddleware <span class="token operator">=</span> <span class="token function">expressJWT</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">secret</span><span class="token operator">:</span> <span class="token string">'supersecret'</span><span class="token punctuation">,</span> <span class="token literal-property property">algorithms</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'HS256'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token function-variable function">getToken</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">req</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> req<span class="token punctuation">.</span>session<span class="token punctuation">.</span>token <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/private'</span><span class="token punctuation">,</span> jwtMiddleware<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token string">'private.ejs'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">email</span><span class="token operator">:</span> req<span class="token punctuation">.</span>user<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>This route uses the <code class="language-text">jwtMiddleware</code>, which is created using the <code class="language-text">express-jwt</code> library. If the JWT token is not in the session, an error will be thrown and the user can't access the page. Else, the <code class="language-text">private.ejs</code> view is rendered.</p><p>Create <code class="language-text">views/private.ejs</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>IE=edge<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Private<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">integrity</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3<span class="token punctuation">"</span></span> <span class="token attr-name">crossorigin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>anonymous<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>container mx-auto mt-4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Hello, <%= email %><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/logout<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Log Out<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre></div><p>This will only show a greeting to the user with their email and a log-out button.</p><h2 id="create-log-out-route">Create Log Out Route </h2><p>Finally, you just need to add a log-out route. </p><p>In <code class="language-text">index.js</code>, add the <code class="language-text">logout</code> route:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/logout'</span><span class="token punctuation">,</span> jwtMiddleware<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> req<span class="token punctuation">.</span>session<span class="token punctuation">.</span><span class="token function">destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>This just destroys the session to remove the JWT token from the session, which would disallow the user from accessing the private page. Then, the user is redirected to the home page.</p><h2 id="test-it-out">Test it Out </h2><p>Let's test it all out. First, run the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>This will create the SQLite database <code class="language-text">db.sqlite</code> and start the server at <code class="language-text">localhost:3000</code>. Open it in your browser. You'll see the signup form.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-21-at-8.24.56-PM.png" class="kg-image" alt="How to Add Authentication with Google Authenticator in Node.js" loading="lazy" width="2000" height="461" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-21-at-8.24.56-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-21-at-8.24.56-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-21-at-8.24.56-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2022/01/Screen-Shot-2022-01-21-at-8.24.56-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>Enter an email and click Sign Up. You'll then be redirected to add the 2FA with the authenticator app. You'll see a QRCode with a code input to enter the code after scanning the QRCode.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-21-at-8.26.13-PM.png" class="kg-image" alt="How to Add Authentication with Google Authenticator in Node.js" loading="lazy" width="2000" height="751" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-21-at-8.26.13-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-21-at-8.26.13-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-21-at-8.26.13-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2022/01/Screen-Shot-2022-01-21-at-8.26.13-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>After you scan the QRCode in Google's Authenticator app or any other authenticator app, you'll see a 6-digit code in the app. Enter that code in the 2FA Code field and click Submit. If it's correct, you'll be redirected to the private page.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-21-at-8.28.12-PM.png" class="kg-image" alt="How to Add Authentication with Google Authenticator in Node.js" loading="lazy" width="1322" height="394" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-21-at-8.28.12-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-21-at-8.28.12-PM.png 1000w, https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-21-at-8.28.12-PM.png 1322w" sizes="(min-width: 720px) 720px"/></figure><p>Try to log out now and go to the login page from the sign up (home) page. You'll see a form to enter an email and a code.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-21-at-8.30.01-PM.png" class="kg-image" alt="How to Add Authentication with Google Authenticator in Node.js" loading="lazy" width="2000" height="523" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-21-at-8.30.01-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-21-at-8.30.01-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-21-at-8.30.01-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2022/01/Screen-Shot-2022-01-21-at-8.30.01-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>Enter the email you just used to create the account and the code from the Authenticator app. If it's all correct, you'll be authenticated and redirected to the private page.</p><h2 id="conclusion">Conclusion</h2><p>In this tutorial, you learned how to add authentication with time-based one-time password apps like Google Authenticator. Ideally, your website should have an initial authentication method (for example, with a password set by the user), then this method will be used to add an extra layer of authentication. </p><p>Also, secrets in your app should be kept in environment variables and you should handle errors and validation. This app was kept simple for the sake of the tutorial.</p>]]></content:encoded></item><item><title><![CDATA[How to Track the Rank of Keywords in Google SERPs using Python]]></title><description><![CDATA[In this post, we will learn how to track the rank of pages in google for any keyword using Python. We will create a tool like SEMrush & Ahrefs with coding.]]></description><link>https://blog.shahednasser.com/track-keywords-in-google-using-python/</link><guid isPermaLink="false">Ghost__Post__63404f3c4e918d05f3537ce0</guid><dc:creator><![CDATA[Manthan Koolwal]]></dc:creator><pubDate>Fri, 07 Oct 2022 16:24:53 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/c7f2d7cb0a35bfefe5dee8bd3423a8af/serp-python.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/c7f2d7cb0a35bfefe5dee8bd3423a8af/serp-python.png" alt="How to Track the Rank of Keywords in Google SERPs using Python"/><p>Keyword rank tracking is very common in the world of marketing. Many marketing teams use expensive tools to track their website ranks for multiple keywords on a regular basis. Since they have to do it on a daily basis this comes quite costly for new businesses, individuals, or startups.</p><p>So in this post, we will create a crawler that will keep you updated with your latest rank on <strong>any keyword you want to track</strong>.</p><p>We will create a web scraper to <a href="https://www.scrapingdog.com/blog/scrape-google-search-results/">scrape google search results</a> using python. I am assuming that you have already installed python on your computer. We will begin with coding the web scraper.</p><h2 id="let%E2%80%99s-code">Let’s code</h2><p>First, we need to install all the necessary libraries.</p><p>· Requests</p><p>· BeautifulSoup</p><p>Create a folder and then install these libraries:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> googlescraper pip <span class="token function">install</span> requests pip <span class="token function">install</span> beautifulsoup4</code></pre></div><p>Then we will import these libraries into our file. You can name the file <code class="language-text">googlescraper.py</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python"><span class="token keyword">import</span> requests <span class="token keyword">from</span> bs4 <span class="token keyword">import</span> BeautifulSoup</code></pre></div><p>Our target URL will change according to the keyword we want to scrape but the basic structure of the google URL will remain the same.</p><p>Google URL structure — <code class="language-text">https://www.google.com/search?q={any keyword or phrase}</code></p><p>For this blog post, our target keyword will be “scrape prices” and we have to find the rank of the domain <code class="language-text">christian-schou.dk</code> at this keyword.</p><p>So, our target URL will be<a href="https://www.google.com/search?q=scrape+prices"> this</a>.</p><p>Let us first check whether this domain is present in the first 10 results or not.As you can see page URLs are located inside class <em><code class="language-text">jGGQ5e</code></em> and then into<em> <code class="language-text">yuRUbf</code>. </em>After this, we have to find a tag inside class <em><code class="language-text">yuRUbf</code></em> and then get the value of <em><code class="language-text">href</code></em> tag.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python">headers<span class="token operator">=</span><span class="token punctuation">{</span>‘User<span class="token operator">-</span>Agent’<span class="token punctuation">:</span>’Mozilla<span class="token operator">/</span><span class="token number">5.0</span> <span class="token punctuation">(</span>Windows NT <span class="token number">10.0</span><span class="token punctuation">;</span> Win64<span class="token punctuation">;</span> x64<span class="token punctuation">)</span> AppleWebKit<span class="token operator">/</span><span class="token number">537.36</span> <span class="token punctuation">(</span>KHTML<span class="token punctuation">,</span> like Gecko<span class="token punctuation">)</span> Chrome<span class="token operator">/</span><span class="token number">104.0</span><span class="token number">.0</span><span class="token number">.0</span> Safari<span class="token operator">/</span><span class="token number">537.36</span><span class="token string">',’referer’:’https://www.google.com'</span><span class="token punctuation">}</span> target_url<span class="token operator">=</span>’https<span class="token punctuation">:</span><span class="token operator">//</span>www<span class="token punctuation">.</span>google<span class="token punctuation">.</span>com<span class="token operator">/</span>search?q<span class="token operator">=</span>scrape<span class="token operator">+</span>prices' resp <span class="token operator">=</span> requests<span class="token punctuation">.</span>get<span class="token punctuation">(</span>target_url<span class="token punctuation">,</span> headers<span class="token operator">=</span>headers<span class="token punctuation">)</span> <span class="token keyword">print</span><span class="token punctuation">(</span>resp<span class="token punctuation">.</span>status_code<span class="token punctuation">)</span></code></pre></div><p>Here we have declared some headers like User-Agent and a Referer to act like a standard browser and not as a crawler.</p><p>Then we declared our target URL and finally made the GET request using the requests library. Once we run this code you should see <strong>200</strong> on your terminal.</p><p>Now, our target is to find our domain. Let’s find it using BS4.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python">soup<span class="token operator">=</span>BeautifulSoup<span class="token punctuation">(</span>resp<span class="token punctuation">.</span>text<span class="token punctuation">,</span>’html<span class="token punctuation">.</span>parser’<span class="token punctuation">)</span> results <span class="token operator">=</span> soup<span class="token punctuation">.</span>find_all<span class="token punctuation">(</span>“div”<span class="token punctuation">,</span><span class="token punctuation">{</span>“<span class="token keyword">class</span>”<span class="token punctuation">:</span>”jGGQ5e”<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>We have used <code class="language-text">html.parser</code> inside the BS4 library to create a tree of our HTML code. <strong><code class="language-text">results</code></strong> array, you will get the HTML code of all the top 10 results.</p><p>In this list, we have to search our links one by one. For that, we are going to use for loop.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python"><span class="token keyword">from</span> urllib<span class="token punctuation">.</span>parse <span class="token keyword">import</span> urlparse <span class="token keyword">for</span> x <span class="token keyword">in</span> <span class="token builtin">range</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token builtin">len</span><span class="token punctuation">(</span>results<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span> domain<span class="token operator">=</span>urlparse<span class="token punctuation">(</span>results<span class="token punctuation">[</span>x<span class="token punctuation">]</span><span class="token punctuation">.</span>find<span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">,</span><span class="token punctuation">{</span><span class="token string">"class"</span><span class="token punctuation">:</span><span class="token string">"yuRUbf"</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>find<span class="token punctuation">(</span><span class="token string">"a"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"href"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>netloc <span class="token keyword">if</span><span class="token punctuation">(</span>domain <span class="token operator">==</span> <span class="token string">'blog.christian-schou.dk'</span><span class="token punctuation">)</span><span class="token punctuation">:</span> found<span class="token operator">=</span><span class="token boolean">True</span> position<span class="token operator">=</span>x<span class="token operator">+</span><span class="token number">1</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">else</span><span class="token punctuation">:</span> found<span class="token operator">=</span><span class="token boolean">False</span> <span class="token keyword">if</span><span class="token punctuation">(</span>found<span class="token operator">==</span><span class="token boolean">True</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"Found at position"</span><span class="token punctuation">,</span> position<span class="token punctuation">)</span> <span class="token keyword">else</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"not found in top"</span><span class="token punctuation">,</span> <span class="token builtin">len</span><span class="token punctuation">(</span>results<span class="token punctuation">)</span><span class="token punctuation">)</span> </code></pre></div><p>We have used<a href="https://docs.python.org/3/library/urllib.parse.html"> urlparse</a> library to parse out the domain from the link. Then we are trying to match our domain with the domain we extracted.</p><p>If it matches we will get the position and if it does not match then it will print not found.</p><p>Let us run this code and let’s see what we get.</p><p>Well, the request was successful as I can see a 200 but we could find this domain in the top 10 results.</p><p>Let’s search for it in the top 20 results, but for that, we need to change the target URL and add param &num=20 to our google URL.</p><p>Google URL will become <code class="language-text">https://www.google.com/search?q=scrape+prices&num=20</code></p><p>Run the program again and check whether you see this domain or not.</p><p>This time I found the domain in the 18th position on Google search results.</p><p>So, the rank of this domain for “scrape prices” is 18th in my country. This position will change according to the country as google display different results in different country.</p><p>This is how you can track the rank of any domain for any keyword. If you want to track it for different countries then you can use google search result scraper.</p><p>Going forward you can also create an SEO tool just like<a href="https://ahrefs.com/"> Ahref</a> and<a href="https://www.semrush.com/"> Semrush</a> or you can create a lead generation tool like<a href="https://snov.io/"> Snov</a>.</p><h3 id="complete-code">Complete Code</h3><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python"><span class="token keyword">import</span> requests <span class="token keyword">from</span> bs4 <span class="token keyword">import</span> BeautifulSoup <span class="token keyword">from</span> urllib<span class="token punctuation">.</span>parse <span class="token keyword">import</span> urlparse headers<span class="token operator">=</span><span class="token punctuation">{</span>‘User<span class="token operator">-</span>Agent’<span class="token punctuation">:</span>’Mozilla<span class="token operator">/</span><span class="token number">5.0</span> <span class="token punctuation">(</span>Windows NT <span class="token number">10.0</span><span class="token punctuation">;</span> Win64<span class="token punctuation">;</span> x64<span class="token punctuation">)</span> AppleWebKit<span class="token operator">/</span><span class="token number">537.36</span> <span class="token punctuation">(</span>KHTML<span class="token punctuation">,</span> like Gecko<span class="token punctuation">)</span> Chrome<span class="token operator">/</span><span class="token number">104.0</span><span class="token number">.0</span><span class="token number">.0</span> Safari<span class="token operator">/</span><span class="token number">537.36</span><span class="token string">',’referer’:’https://www.google.com'</span><span class="token punctuation">}</span> target_url<span class="token operator">=</span>’https<span class="token punctuation">:</span><span class="token operator">//</span>www<span class="token punctuation">.</span>google<span class="token punctuation">.</span>com<span class="token operator">/</span>search?q<span class="token operator">=</span>scrape<span class="token operator">+</span>prices<span class="token operator">&</span>num<span class="token operator">=</span><span class="token number">20</span>' resp <span class="token operator">=</span> requests<span class="token punctuation">.</span>get<span class="token punctuation">(</span>target_url<span class="token punctuation">,</span> headers<span class="token operator">=</span>headers<span class="token punctuation">)</span> <span class="token keyword">print</span><span class="token punctuation">(</span>resp<span class="token punctuation">.</span>status_code<span class="token punctuation">)</span> soup<span class="token operator">=</span>BeautifulSoup<span class="token punctuation">(</span>resp<span class="token punctuation">.</span>text<span class="token punctuation">,</span>’html<span class="token punctuation">.</span>parser’<span class="token punctuation">)</span> results <span class="token operator">=</span> soup<span class="token punctuation">.</span>find_all<span class="token punctuation">(</span>“div”<span class="token punctuation">,</span><span class="token punctuation">{</span>“<span class="token keyword">class</span>”<span class="token punctuation">:</span>”jGGQ5e”<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment"># print(results)</span> <span class="token keyword">for</span> x <span class="token keyword">in</span> <span class="token builtin">range</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token builtin">len</span><span class="token punctuation">(</span>results<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span> domain<span class="token operator">=</span>urlparse<span class="token punctuation">(</span>results<span class="token punctuation">[</span>x<span class="token punctuation">]</span><span class="token punctuation">.</span>find<span class="token punctuation">(</span>“div”<span class="token punctuation">,</span><span class="token punctuation">{</span>“<span class="token keyword">class</span>”<span class="token punctuation">:</span>”yuRUbf”<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>find<span class="token punctuation">(</span>“a”<span class="token punctuation">)</span><span class="token punctuation">.</span>get<span class="token punctuation">(</span>“href”<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>netloc <span class="token keyword">if</span><span class="token punctuation">(</span>domain <span class="token operator">==</span> ‘blog<span class="token punctuation">.</span>christian<span class="token operator">-</span>schou<span class="token punctuation">.</span>dk’<span class="token punctuation">)</span><span class="token punctuation">:</span> found<span class="token operator">=</span><span class="token boolean">True</span> position<span class="token operator">=</span>x<span class="token operator">+</span><span class="token number">1</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">else</span><span class="token punctuation">:</span> found<span class="token operator">=</span><span class="token boolean">False</span> <span class="token keyword">if</span><span class="token punctuation">(</span>found<span class="token operator">==</span><span class="token boolean">True</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span>“Found at position”<span class="token punctuation">,</span> position<span class="token punctuation">)</span> <span class="token keyword">else</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span>“<span class="token keyword">not</span> found <span class="token keyword">in</span> top”<span class="token punctuation">,</span> <span class="token builtin">len</span><span class="token punctuation">(</span>results<span class="token punctuation">)</span><span class="token punctuation">)</span> </code></pre></div><h2 id="running-the-code-every-24-hours">Running the code every 24 hours</h2><p>Let’s say you want to track your position every 24 hours because you are putting lots of effort into marketing and you want to see results on daily basis.</p><p>For that you can mail yourself the current position every morning, this will keep you updated.We will use<a href="https://schedule.readthedocs.io/en/stable/"> schedule</a> library to implement this task.</p><h3 id="complete-code-1">Complete Code</h3><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python"><span class="token keyword">import</span> requests <span class="token keyword">from</span> bs4 <span class="token keyword">import</span> BeautifulSoup <span class="token keyword">from</span> urllib<span class="token punctuation">.</span>parse <span class="token keyword">import</span> urlparse <span class="token keyword">import</span> schedule <span class="token keyword">import</span> time <span class="token keyword">def</span> <span class="token function">tracker</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> headers<span class="token operator">=</span><span class="token punctuation">{</span>‘User<span class="token operator">-</span>Agent’<span class="token punctuation">:</span>’Mozilla<span class="token operator">/</span><span class="token number">5.0</span> <span class="token punctuation">(</span>Windows NT <span class="token number">10.0</span><span class="token punctuation">;</span> Win64<span class="token punctuation">;</span> x64<span class="token punctuation">)</span> AppleWebKit<span class="token operator">/</span><span class="token number">537.36</span> <span class="token punctuation">(</span>KHTML<span class="token punctuation">,</span> like Gecko<span class="token punctuation">)</span> Chrome<span class="token operator">/</span><span class="token number">104.0</span><span class="token number">.0</span><span class="token number">.0</span> Safari<span class="token operator">/</span><span class="token number">537.36</span><span class="token string">',’referer’:’https://www.google.com'</span><span class="token punctuation">}</span> target_url<span class="token operator">=</span>’https<span class="token punctuation">:</span><span class="token operator">//</span>www<span class="token punctuation">.</span>google<span class="token punctuation">.</span>com<span class="token operator">/</span>search?q<span class="token operator">=</span>scrape<span class="token operator">+</span>prices<span class="token operator">&</span>num<span class="token operator">=</span><span class="token number">20</span>' resp <span class="token operator">=</span> requests<span class="token punctuation">.</span>get<span class="token punctuation">(</span>target_url<span class="token punctuation">,</span> headers<span class="token operator">=</span>headers<span class="token punctuation">)</span> <span class="token keyword">print</span><span class="token punctuation">(</span>resp<span class="token punctuation">.</span>status_code<span class="token punctuation">)</span> soup<span class="token operator">=</span>BeautifulSoup<span class="token punctuation">(</span>resp<span class="token punctuation">.</span>text<span class="token punctuation">,</span>’html<span class="token punctuation">.</span>parser’<span class="token punctuation">)</span> results <span class="token operator">=</span> soup<span class="token punctuation">.</span>find_all<span class="token punctuation">(</span>“div”<span class="token punctuation">,</span><span class="token punctuation">{</span>“<span class="token keyword">class</span>”<span class="token punctuation">:</span>”jGGQ5e”<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment"># print(results)</span> <span class="token keyword">for</span> x <span class="token keyword">in</span> <span class="token builtin">range</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token builtin">len</span><span class="token punctuation">(</span>results<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span> domain<span class="token operator">=</span>urlparse<span class="token punctuation">(</span>results<span class="token punctuation">[</span>x<span class="token punctuation">]</span><span class="token punctuation">.</span>find<span class="token punctuation">(</span>“div”<span class="token punctuation">,</span><span class="token punctuation">{</span>“<span class="token keyword">class</span>”<span class="token punctuation">:</span>”yuRUbf”<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>find<span class="token punctuation">(</span>“a”<span class="token punctuation">)</span><span class="token punctuation">.</span>get<span class="token punctuation">(</span>“href”<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>netloc <span class="token keyword">if</span><span class="token punctuation">(</span>domain <span class="token operator">==</span> ‘blog<span class="token punctuation">.</span>christian<span class="token operator">-</span>schou<span class="token punctuation">.</span>dk’<span class="token punctuation">)</span><span class="token punctuation">:</span> found<span class="token operator">=</span><span class="token boolean">True</span> position<span class="token operator">=</span>x<span class="token operator">+</span><span class="token number">1</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">else</span><span class="token punctuation">:</span> found<span class="token operator">=</span><span class="token boolean">False</span> position<span class="token operator">=</span>x<span class="token operator">+</span><span class="token number">1</span> <span class="token keyword">if</span><span class="token punctuation">(</span>found<span class="token operator">==</span><span class="token boolean">True</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span>“Found at position”<span class="token punctuation">,</span> position<span class="token punctuation">)</span> <span class="token keyword">else</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span>“<span class="token keyword">not</span> found <span class="token keyword">in</span> top “<span class="token operator">+</span> <span class="token builtin">str</span><span class="token punctuation">(</span>position<span class="token punctuation">)</span><span class="token operator">+</span> “ results”<span class="token punctuation">)</span> <span class="token keyword">if</span> __name__ <span class="token operator">==</span> “__main__”<span class="token punctuation">:</span> schedule<span class="token punctuation">.</span>every<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">.</span>seconds<span class="token punctuation">.</span>do<span class="token punctuation">(</span>tracker<span class="token punctuation">)</span> <span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span> schedule<span class="token punctuation">.</span>run_pending<span class="token punctuation">(</span><span class="token punctuation">)</span> </code></pre></div><p>Here we are running the schedule every 5 seconds just to test whether it will work for us or not. Once you run it you will get the results like this.</p><p>Now, to run it every day or after every 24 hours you can use:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python">schedule<span class="token punctuation">.</span>every<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>day<span class="token punctuation">.</span>at<span class="token punctuation">(</span><span class="token string">"12:00"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>do<span class="token punctuation">(</span>job<span class="token punctuation">)</span></code></pre></div><p>Now, let us mail ourselves these results to keep us updated with the latest position on google. For this task, we will use<a href="https://docs.python.org/3/library/smtplib.html"> smtplib</a> library.</p><h3 id="mail">Mail</h3><div class="kg-card kg-code-card gatsby-highlight" data-language="python"><pre class="language-python"><code class="language-python"><span class="token keyword">import</span> requests <span class="token keyword">from</span> bs4 <span class="token keyword">import</span> BeautifulSoup <span class="token keyword">from</span> urllib<span class="token punctuation">.</span>parse <span class="token keyword">import</span> urlparse <span class="token keyword">import</span> schedule <span class="token keyword">import</span> time <span class="token keyword">import</span> smtplib<span class="token punctuation">,</span> ssl <span class="token keyword">def</span> <span class="token function">mail</span><span class="token punctuation">(</span>position<span class="token punctuation">)</span><span class="token punctuation">:</span> attackMsg <span class="token operator">=</span> position server <span class="token operator">=</span> smtplib<span class="token punctuation">.</span>SMTP<span class="token punctuation">(</span>‘smtp<span class="token punctuation">.</span>gmail<span class="token punctuation">.</span>com’<span class="token punctuation">,</span> <span class="token number">587</span><span class="token punctuation">)</span> server<span class="token punctuation">.</span>ehlo<span class="token punctuation">(</span><span class="token punctuation">)</span> server<span class="token punctuation">.</span>starttls<span class="token punctuation">(</span><span class="token punctuation">)</span> server<span class="token punctuation">.</span>login<span class="token punctuation">(</span>“<span class="token keyword">from</span>@gmail<span class="token punctuation">.</span>com”<span class="token punctuation">,</span> “xxxx”<span class="token punctuation">)</span> SUBJECT <span class="token operator">=</span> “Position Alert” message <span class="token operator">=</span> ‘From<span class="token punctuation">:</span> <span class="token keyword">from</span>@gmail<span class="token punctuation">.</span>com \nSubject<span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>\n\n<span class="token punctuation">{</span><span class="token punctuation">}</span>’<span class="token punctuation">.</span><span class="token builtin">format</span><span class="token punctuation">(</span>SUBJECT<span class="token punctuation">,</span> attackMsg<span class="token punctuation">)</span> server<span class="token punctuation">.</span>sendmail<span class="token punctuation">(</span>“<span class="token keyword">from</span>@gmail<span class="token punctuation">.</span>com”<span class="token punctuation">,</span> ‘send_to@gmail<span class="token punctuation">.</span>com’<span class="token punctuation">,</span> message<span class="token punctuation">)</span> server<span class="token punctuation">.</span>quit<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">True</span> <span class="token keyword">def</span> <span class="token function">tracker</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> headers<span class="token operator">=</span><span class="token punctuation">{</span>‘User<span class="token operator">-</span>Agent’<span class="token punctuation">:</span>’Mozilla<span class="token operator">/</span><span class="token number">5.0</span> <span class="token punctuation">(</span>Windows NT <span class="token number">10.0</span><span class="token punctuation">;</span> Win64<span class="token punctuation">;</span> x64<span class="token punctuation">)</span> AppleWebKit<span class="token operator">/</span><span class="token number">537.36</span> <span class="token punctuation">(</span>KHTML<span class="token punctuation">,</span> like Gecko<span class="token punctuation">)</span> Chrome<span class="token operator">/</span><span class="token number">104.0</span><span class="token number">.0</span><span class="token number">.0</span> Safari<span class="token operator">/</span><span class="token number">537.36</span><span class="token string">',’referer’:’https://www.google.com'</span><span class="token punctuation">}</span> target_url<span class="token operator">=</span>’https<span class="token punctuation">:</span><span class="token operator">//</span>www<span class="token punctuation">.</span>google<span class="token punctuation">.</span>com<span class="token operator">/</span>search?q<span class="token operator">=</span>scrape<span class="token operator">+</span>prices<span class="token operator">&</span>num<span class="token operator">=</span><span class="token number">20</span>' resp <span class="token operator">=</span> requests<span class="token punctuation">.</span>get<span class="token punctuation">(</span>target_url<span class="token punctuation">,</span> headers<span class="token operator">=</span>headers<span class="token punctuation">)</span> <span class="token keyword">print</span><span class="token punctuation">(</span>resp<span class="token punctuation">.</span>status_code<span class="token punctuation">)</span> soup<span class="token operator">=</span>BeautifulSoup<span class="token punctuation">(</span>resp<span class="token punctuation">.</span>text<span class="token punctuation">,</span>’html<span class="token punctuation">.</span>parser’<span class="token punctuation">)</span> results <span class="token operator">=</span> soup<span class="token punctuation">.</span>find_all<span class="token punctuation">(</span>“div”<span class="token punctuation">,</span><span class="token punctuation">{</span>“<span class="token keyword">class</span>”<span class="token punctuation">:</span>”jGGQ5e”<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment"># print(results)</span> <span class="token keyword">for</span> x <span class="token keyword">in</span> <span class="token builtin">range</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token builtin">len</span><span class="token punctuation">(</span>results<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span> domain<span class="token operator">=</span>urlparse<span class="token punctuation">(</span>results<span class="token punctuation">[</span>x<span class="token punctuation">]</span><span class="token punctuation">.</span>find<span class="token punctuation">(</span>“div”<span class="token punctuation">,</span><span class="token punctuation">{</span>“<span class="token keyword">class</span>”<span class="token punctuation">:</span>”yuRUbf”<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>find<span class="token punctuation">(</span>“a”<span class="token punctuation">)</span><span class="token punctuation">.</span>get<span class="token punctuation">(</span>“href”<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>netloc <span class="token keyword">if</span><span class="token punctuation">(</span>domain <span class="token operator">==</span> ‘blog<span class="token punctuation">.</span>christian<span class="token operator">-</span>schou<span class="token punctuation">.</span>dk’<span class="token punctuation">)</span><span class="token punctuation">:</span> found<span class="token operator">=</span><span class="token boolean">True</span> position<span class="token operator">=</span>x<span class="token operator">+</span><span class="token number">1</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">else</span><span class="token punctuation">:</span> found<span class="token operator">=</span><span class="token boolean">False</span> position<span class="token operator">=</span>x<span class="token operator">+</span><span class="token number">1</span> <span class="token keyword">if</span><span class="token punctuation">(</span>found<span class="token operator">==</span><span class="token boolean">True</span><span class="token punctuation">)</span><span class="token punctuation">:</span> message<span class="token operator">=</span>”Found at position “<span class="token operator">+</span> <span class="token builtin">str</span><span class="token punctuation">(</span>position<span class="token punctuation">)</span> mail<span class="token punctuation">(</span>message<span class="token punctuation">)</span> <span class="token keyword">else</span><span class="token punctuation">:</span> message<span class="token operator">=</span>”<span class="token keyword">not</span> found <span class="token keyword">in</span> top “<span class="token operator">+</span> <span class="token builtin">str</span><span class="token punctuation">(</span>position<span class="token punctuation">)</span><span class="token operator">+</span> “ results” mail<span class="token punctuation">(</span>message<span class="token punctuation">)</span> <span class="token keyword">if</span> __name__ <span class="token operator">==</span> “__main__”<span class="token punctuation">:</span> schedule<span class="token punctuation">.</span>every<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>day<span class="token punctuation">.</span>at<span class="token punctuation">(</span><span class="token string">"12:00"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>do<span class="token punctuation">(</span>job<span class="token punctuation">)</span> <span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span> schedule<span class="token punctuation">.</span>run_pending<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre></div><p>In the mail function, we are making a login attempt to our Gmail account with the password.</p><p>Then we have declared the subject and the message that will be sent to us. And finally we used .senemail function to send the email alert. This will send an email alert every 24 hours directly to your inbox.</p><p>Now, you might wonder if we stop the script our scheduler will stop working. Yes, you are right and to tackle it we are going to use<a href="https://janakiev.com/blog/python-background/"> nohup</a>.</p><p>Nohup will ignore the hangup signal and will keep running your script even if you stop it.</p><p>I leave this task to you as homework in a hope that you will learn something new and unique.</p><h2 id="conclusion">Conclusion</h2><p>In this post, we learned how we can create a task that can run at any given interval of time. We used four libraries i.e. requests, BS4, schedule, and smtplib to complete this task.</p><p>Now it does not stop here, you can create any type of scheduler like news updates, stock updates, etc. I am sure python will make your job fast and simple.</p>]]></content:encoded></item><item><title><![CDATA[What are Prime Numbers?]]></title><description><![CDATA[Prime numbers, by definition, are integers that could not be decomposed into two new numbers.]]></description><link>https://blog.shahednasser.com/what-are-prime-numbers/</link><guid isPermaLink="false">Ghost__Post__62dc5a284e918d05f3537766</guid><category><![CDATA[Mathematics]]></category><dc:creator><![CDATA[Mohammad Nasser]]></dc:creator><pubDate>Sat, 23 Jul 2022 20:32:09 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/bbbf65b4913cef0a582d0ec991ad0b7d/What-are-Prime-Numbers.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/bbbf65b4913cef0a582d0ec991ad0b7d/What-are-Prime-Numbers.jpg" alt="What are Prime Numbers?"/><p>Prime numbers, by definition, are integers that could not be decomposed into two new numbers. In Number theory, a prime number P is an integer that has just two divisors: 1 and P. There is no known sequence in mathematics that could describe the chain of prime numbers.</p><p>A long period ago, Mathematicians had a lot of challenges to prove that a number is prime. Moreover, a mathematician now could do new research that could be published in great journals just if he found a new prime number! The largest known prime number till now (May 2022) is the number 2^{82,589,933 }− 1, which has 24,862,048 digits!</p><p>So, what is the magic in prime numbers?! And why are mathematicians interested in it?! The answer is in the following theorem in Number theory, which says that "Any integer n could write as a product of the power of prime numbers". </p><p>For example 4=2x2, 6=2x3, 8=2^3, and 9=3^2, with 2 and 3 being primes. What does that mean? This means that if you want to prove any theorem in the whole set of integers, it is enough to prove it on the set of prime numbers since all numbers could return to the power of prime numbers.</p><p>Although there are some theorems that could provide a way to approximate the number of prime numbers less than or equal to a given number n (The prime number theorem for example), we still have a lot of research to do in this part of the field of Number theory.</p><p>Mathematicians will never stop trying to find a way to test a number if it is prime or not, could it possible?</p>]]></content:encoded></item><item><title><![CDATA[What is Representation Theory?]]></title><description><![CDATA[Representation theory is a field of Mathematics that has lots of applications in physics, number theory, and cryptography.]]></description><link>https://blog.shahednasser.com/what-is-representation-theory/</link><guid isPermaLink="false">Ghost__Post__625dc17339840e1ac28750f8</guid><category><![CDATA[Mathematics]]></category><dc:creator><![CDATA[Mohammad Nasser]]></dc:creator><pubDate>Mon, 18 Apr 2022 19:54:03 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/e11db6c9495534768e7a31d8655c4223/What-is-Representation-Theory.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/e11db6c9495534768e7a31d8655c4223/What-is-Representation-Theory.jpg" alt="What is Representation Theory?"/><p>Representation theory is a field of Mathematics, known in 1896 by the German mathematician Frobenius, that has lots of applications in physics, number theory, and cryptography.</p><p>In representation theory, mathematicians study representations of algebras (group, rings, topological spaces) by representing their elements as linear transformations of vector spaces. More specifically, a representation makes abstract algebraic objects more concrete by transforming them into matrices.</p><p>The importance of representation theory is that abstract problems are reduced to problems in linear algebra which is a well-known theory in mathematics.</p><p>An important branch of representation theory is "group<br>representation theory", in which the group elements are represented by invertible matrices. Consequently, we work with matrix multiplication instead of working with the original group operation.</br></p><p>More exactly, a "representation" of group G means a homomorphism mapping from G to the automorphism group of the object.</p><p>This asks for a possible way to view a group as a permutation group or a linear group. More narrowly, it considers homomorphisms from the group into the matrix group GLn(C), where C is most frequently the field of complex numbers.</p><p>Also, representation theory depends heavily on the type of vector space on which the algebra acts. One must consider the type of field over which the vector space is defined. The most important cases are the field of complex numbers and the field of real numbers.</p>]]></content:encoded></item><item><title><![CDATA[Will Apple Release Security Updates for the iOS 14 after the iOS 15 Launch?]]></title><description><![CDATA[Regardless of whether you stick with iOS 14 or not, you must fix any problems with your device for the best experience.]]></description><link>https://blog.shahednasser.com/will-apple-release-security-updates-for-the-ios-14-after-the-ios-15-launch/</link><guid isPermaLink="false">Ghost__Post__6200da7660a9ab05cc5e6a97</guid><category><![CDATA[News]]></category><dc:creator><![CDATA[Helena Barnes]]></dc:creator><pubDate>Mon, 07 Feb 2022 10:28:28 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/672c2500d5fcb8d7432b010e8985a5de/How-to-Style-a-Scrollbar-with-CSS-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/672c2500d5fcb8d7432b010e8985a5de/How-to-Style-a-Scrollbar-with-CSS-2.jpg" alt="Will Apple Release Security Updates for the iOS 14 after the iOS 15 Launch?"/><p>Apple has recently launched its latest iOS system that many people have been waiting for. The iOS 15, as you might know, brings in certain changes to your iPhone’s system. It also brings in new features apart from enhancing the already existing ones. However, many users reportedly want to continue with iOS 14. After all, it is among the best iOS system versions until now.</p><p>So, Apple had announced that they would keep releasing security updates for iOS 14. This has assured users that they can keep using their existing system with the latest security features. Regardless of whether you stick with iOS 14 or not, you must fix any problems with your device for the best experience. So, reach out to a reliable <a href="https://iphonerepair.ae/">iPhone repair service</a> for quick and efficient solutions.</p><h2 id="what-do-we-know-about-ios-14-security-updates">What do We Know about iOS 14 Security Updates?</h2><p>Apple had initially promised security updates to iOS 14 users. And, they came out with the iOS 14.8.1 sometime after the iOS 15 launch. This update included fixes for various bugs in your iPhone. It also brought in certain improvements to the existing security features. Moreover, you can also find new security features in iOS 14.8.1.</p><p>But, the aforementioned update, unfortunately, seems to be the last one for iOS 14 users. According to the latest updates, Apple will not launch further security updates for iOS 14. And, that means you might need to update to iOS 15.</p><p>Are you using iOS 14 on your iPhone? Then, you must check whether you have the option to update to iOS 14.8.1. The security update for iOS 14 is reportedly unavailable to those who do not have it already. In that case, you might need to consider upgrading to iOS 15.</p><h2 id="latest-security-features-you-find-in-ios-14">Latest Security Features You Find in iOS 14</h2><p>Updating to the latest system does not always bring in good results on your device. As it happens, you might often face performance issues after a system update. And that is one of the reasons you might want to stick to iOS 14 for a while.</p><p>Apart from that, it also offers you the optimal security features for your iPhone or iPad. So, here are some of them you must know about</p><h3 id="stronger-wi-fi-security">Stronger Wi-Fi Security</h3><p>Every iOS update brings in stronger security features to your device. After all, that is a necessity due to emerging data security threats. As it happens, cybercriminals quite frequently use Wi-Fi networks to breach connected devices. And, the iOS 14 comes with optimal security measures for your Wi-Fi network.</p><p>It allows you to use a private IP address to prevent cybercriminals from tracking your device. You can enable this feature from the IP address section in your Wi-Fi settings.</p><p>This feature protects your device when it is connected to a public Wi-Fi network.</p><p>So, you can now connect to such networks without any worries. And, this security feature would probably be included in iOS 15 as it is an important one. You might also get an enhanced version of it in the latest system version.</p><h3 id="alerts-when-apps-monitor-your-clipboard">Alerts when Apps Monitor Your Clipboard</h3><p>You might often copy various texts, links, or other information on your device’s clipboard. And, some of the apps on your device might be able to monitor these pieces of information. You might want to prevent them from doing that due to various reasons.</p><p>In iOS 14, you can set your device to alert you when an app is monitoring the clipboard. You will get notifications whenever the clipboard is being monitored. This feature was not present in the earlier iOS versions. However, you might get it in the latest versions as it is quite an essential feature.</p><h3 id="permission-required-for-app-tracking">Permission Required for App Tracking</h3><p>The apps on your iPhone might track you on the internet for various purposes. And, iOS 14 offers you the option to disable them from doing that. You can refuse them permission to track your device from the Tracking section in the Privacy settings. This is yet another useful security feature that helps you maintain your online privacy.</p><h3 id="advanced-camera-and-microphone-usage-alerts">Advanced Camera and Microphone Usage Alerts</h3><p>The apps on your iOS device need permission to use the camera microphone in previous system versions as well. But, this security feature was not very effective until iOS 14 came out. Certain apps could get permission to use your camera and microphone fraudulently in older iOS versions.</p><p>The iOS 14 has more advanced features to prevent such instances. And, it seems to be quite effective in doing that. You might get a more enhanced version of this feature if you have the latest security update.</p><h2 id="what-do-you-get-by-updating-ios-15">What do You Get by Updating iOS 15?</h2><p>Are you wondering whether you must continue with iOS 14? Then, you must consider what the iOS 15 offers you. And, that would help you make the right decision based on your requirements. Here are the significant features you can get on your iPhone or iPad with iOS 15:</p><h3 id="new-facetime-features">New FaceTime Features</h3><p>FaceTime offers a cluttered view in older versions. And, iOS 15 comes with a fix for that with a grid view of the callers. Moreover, you also get the new Spatial Audio feature in iOS 15. And, that means the audio seems to come from where the caller is located on the screen.</p><p>Apart from that, you can now play media during FaceTime calls with SharePlay. So, the video call experience is enhanced significantly in iOS 15. You might have to get the latest system version to enjoy this feature.</p><h3 id="apple-wallet-enhancements">Apple Wallet Enhancements</h3><p>Lots of people have benefited from the car key feature of the Apple Wallet. And, now, you have the option to add your home, office, and hotel keys to the app as well. This feature has been introduced in iOS 15, so you cannot use it in iOS 14. You need to update your system to the latest version to enjoy features like this one.</p><h3 id="health-app-additions">Health App Additions</h3><p>Among other apps, Health has also seen some additions in iOS 15. It could collect a wide range of data in the older versions. But, the latest update has added a new trend analysis feature as well. This will surely help you monitor your health more effectively. Moreover, you can also share your health data with others over the Health app in iOS 15.</p><h3 id="live-text-and-visual-lookup">Live Text and Visual Lookup</h3><p>You can search with an image on the internet with the new Visual Lookup feature in iOS 15. This feature was already available on other platforms, and you can have it on iOS now. Not only that, but you also get the Live Text feature to copy texts from images. You can then search this text on the web or paste it somewhere for various purposes.</p><h2 id="should-you-update-to-ios-15">Should You Update to iOS 15?</h2><p>As we have seen, iOS 15 has many things to offer you. The features mentioned above are only a few of them. You must also note that there are no further security updates for iOS 14. And, the iOS 15 offers you more advanced security and privacy than previous system versions. So, updating to the latest system version is quite a viable option.</p><p>Also read: <a href="https://internettablettalk.com/first-impression-on-the-latest-iphone/">First Impression On The Latest iPhone</a></p>]]></content:encoded></item><item><title><![CDATA[React useMemo vs useCallback: When To Use?]]></title><description><![CDATA[In this article, we’ll explore React useMemo vs useCallback and when to use useCallback and useMemo. ]]></description><link>https://blog.shahednasser.com/react-usememo-vs-usecallback-when-to-use/</link><guid isPermaLink="false">Ghost__Post__6202b0f410971d0605f2b448</guid><dc:creator><![CDATA[Kateryna Sukhotepla]]></dc:creator><pubDate>Sun, 06 Feb 2022 18:14:00 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/bbf3f1d58f363a9fe7758a95d3e5f1b0/React-useMemo-vs-useCallback-When-To-Use-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/bbf3f1d58f363a9fe7758a95d3e5f1b0/React-useMemo-vs-useCallback-When-To-Use-1.jpg" alt="React useMemo vs useCallback: When To Use?"/><p>React is a free and open-source front-end JavaScript library that can be used to build user interfaces at lightning speed. React is maintained by its community, and many developers are self-taught. Maybe you are one of them…trying to figure out whether you should use useMemo vs useCallback! </p><p>In this article, we’ll explore <a href="https://procoders.tech/blog/difference-between-usememo-and-usecallback/">React useMemo vs useCallback</a> and when to use useCallback and useMemo. </p><h2 id="understanding-the-terms-usememo-vs-usecallback-vs-useeffect">Understanding the Terms: useMemo vs useCallback vs useEffect</h2><p>useCallback, useMemo, and useEffect are used to optimize the performance of React-based applications as components are rerendered. </p><h3 id="usecallback">useCallback</h3><p>useCallback is a react hook that returns a memorized callback when passed a function and a list of dependencies that set the parameters. It’s useful when a component is passing a callback to its child component in order to prevent rendering. It only changes the callback when one of its dependencies is changed. </p><h3 id="usememo">useMemo</h3><p>useMemo is very similar to useCallback. It accepts a function and a list of dependencies, but the difference between useMemo and useCallback is that useMemo returns the memo-ized value returned by the passed function. It only recalculates the value when one of the dependencies changes. It’s very useful if you want to avoid expensive calculations on every render when the returned value isn’t changing. </p><h3 id="useeffect">useEffect </h3><p>We won’t talk about useEffect in detail, but it’s worth noting. The useEffect accepts a function as a first parameter and a list of dependencies as a second parameter. When the dependencies change, it executes the passed function. The hook helps developers perform mutations, subscriptions, logging, and other side effects once all the components have been rendered. </p><h2 id="using-usecallback-vs-usememo-in-practice">Using useCallback vs useMemo in Practice</h2><p>Creating efficient React code is vitally important as HTML pages grow more and more complex over time. Re-rendering large components are expensive and put a strain on the browser through a single-page application, which increases processing time and negatively impacts users. useMemo and useCallback can help developers circumvent non-code-related performance issues. </p><p>When you are wrapping a component with <code class="language-text">React.Memo()</code>, it signals the intent to resume code but doesn’t extend to functions passed as parameters. When a component is wrapped with useCallback, React saves a reference to the function. Passing this reference as a property to new components will shorten your rendering time. </p><h2 id="usememo-and-usecallback-difference">useMemo and useCallback Difference</h2><p>Despite seeming very similar, there are different use cases for each. You should wrap functions with useCallback when passing a function as a dependency to other hooks or wrapping a functional component in <code class="language-text">React.Memo()</code> that accepts your method as a property. You can use useMemo when you are working on functions where the inputs gradually change, where data values aren’t large enough to cause memory issues, or if the parameters are large enough so that the cost of comparison doesn’t outweigh the use of the wrapper. </p><p>useCallback works well in instances where the code would otherwise be recompiled with every call. Memorizing the results can decrease the cost of calling functions over and over again when the inputs change gradually over time. </p><h2 id="when-not-to-use-usememo-and-usecallback">When NOT to use useMemo and useCallback</h2><p>As useful as they are, you shouldn’t use useCallback or useMemo for every function. Each call requires additional work to unravel your function call and make a decision about how to proceed. When you decide whether or not to use these functions, consider your performance levels first. You might want to start by improving your code first. Look for weak spots and try to refactor your JavaScript. (A frontend application performance monitoring tool might be handy at this point!). Think of useCallback and useMemo as a means of fine-tuning React. It can’t fix a badly written codebase, but if everything is already in place, it can take you from good to great. </p><h2 id="conclusion">Conclusion</h2><p>Now that we’ve explored useMemo vs useCallback, you can see how these hooks can be extremely useful. Of course, if you need additional support and guidance, you can hire React developers from anywhere in the world with the right skills and experience to deliver your project using React!</p>]]></content:encoded></item><item><title><![CDATA[What to Expect from Digital Transformation in Automotive in 2022?]]></title><description><![CDATA[Digital transformation is the next big disruptor in the digital automotive industry, with a long history of rapid and disruptive development.]]></description><link>https://blog.shahednasser.com/what-to-expect-from-digital-transformation-in-automotive-in-2022/</link><guid isPermaLink="false">Ghost__Post__61f7d5e360a9ab05cc5e687f</guid><category><![CDATA[Business]]></category><dc:creator><![CDATA[Ava Miller]]></dc:creator><pubDate>Mon, 31 Jan 2022 12:30:50 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/ff6fa0d7ebc0e949dade7ca7f0f1531d/What-to-Expect-from-Digital-Transformation-in-Automotive-in-2022.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/ff6fa0d7ebc0e949dade7ca7f0f1531d/What-to-Expect-from-Digital-Transformation-in-Automotive-in-2022.jpg" alt="What to Expect from Digital Transformation in Automotive in 2022?"/><p>Digital transformation is the next big disruptor in the <a href="https://oroinc.com/b2b-ecommerce/blog/digital-transformation-in-automotive-industry/">digital automotive</a> industry, with a long history of rapid and disruptive development. Automobile manufacturers are increasing their investments in digitization due to increased connectivity, environmental limitations, the Internet of Things, wireless solutions, and rising consumer expectations.</p><p>All areas of the automobile value chain are impacted by technology, including design, manufacture, distribution, and retail. A profusion of customer data is projected to push vehicle investment for many years to come. According to Frost & Sullivan's Future of Mobility report, IT investment would increase from $38 billion to $168 billion by 2025.</p><h2 id="how-will-the-automotive-industrys-digital-transformation-impact-us">How will the automotive industry's digital transformation impact us?</h2><p>Aspects of the automobile purchasing process that trace back to the early twentieth century have stayed primarily unaltered. Even though dealerships and consumers have had access to eCommerce for an extended period, most individuals continue to purchase new automobiles using the traditional method. Despite the widespread adoption of digital products such as iPads, the overall customer experience remained consistent.</p><p>In 2022, consumers of all hues are more ready than ever to purchase online for autos. An increasing number of firms will work to enhance their digital experience and increase consumer engagement through social media, mobile applications, and websites. This pattern is predicted to persist.</p><h2 id="is-the-automotive-industry-digital-transformation-necessary">Is the automotive industry digital transformation necessary?<br/></h2><p>The digital revolution has simplified and improved our lives in the vehicle industry. Digital technology is incorporated into autonomous vehicles, production, maintenance, marketing, and sales. However, these new advancements are not without their downsides.</p><h2 id="automobile-manufacturers-face-digitization-challenges">Automobile manufacturers face digitization challenges<br/></h2><p>Most automobile technical change management efforts are motivated by technological advancements and consumer expectations. The automobile industry is very competitive, as it is entwined with various other businesses. Digital manufacturing, environmental concerns, mobility as a service, and predictive computing all provide a range of benefits and drawbacks. Following are a few instances, which are not in any particular order:</p><h3 id="investment">Investment<br/></h3><p>Financial savings and risk management are high considerations in this challenging economic climate. Automotive businesses will emphasize supply chain visibility, sales efficiency, and customer experience as they strive for efficiency.</p><p>Companies engaged in vehicle digitalization must prioritize the best use cases with the highest return on investment. Predicting the return on investment and discovering relevant use cases for new technology will be fundamental challenges in the automobile business.</p><p>For instance, the press recently called self-driving automobiles the top disruptor. The launch of fully driverless vehicles has been delayed. According to a 2020 Deloitte poll, consumers in Germany (67%) and Japan (61%) are unlikely to spend more than <strong>$600</strong> on self-driving vehicle technology.</p><p>Comparable is the effect of cutting-edge powertrain technology. The overwhelming majority of German and American clientele (58 percent and 54%, respectively) said they would not pay more than <strong>$600</strong> for an alternative-fuel car. These concerns persist, although proponents of these technological advancements have a dubious client desire for technology.</p><h3 id="fear-of-change">Fear of change<br/></h3><p>The industry has a chance to do more to advance crucial innovative ideas. Even as the electric car range increases, there is still some fear about battery power running out. Due to the decentralized nature of the worldwide or national charging infrastructure, automobile manufacturers faceless responsibility for its maintenance. Additionally, there is controversy about whether manufacturers or the government should be responsible for charging infrastructure.</p><p>While business-to-consumer eCommerce has been a hallmark of the automotive aftermarket for decades, other facets of automotive eCommerce have only just begun to embrace digital technologies. Manufacturers are confronted with a slew of challenges. According to a poll, automobile manufacturers predict a 24 percent rise in digital expenditure over the next four years. Nonetheless, the industry's low level of digital maturity and the rapid pace at which these changes are implemented create impediments.</p><h3 id="customer-centricity">Customer-centricity<br/></h3><p>According to a Qualtrics survey, digital transformation is stymied by a lack of client attention. Adopting a customer-centric organizational transformation strategy is crucial for the dealer and service-level implementation of national corporate projects.</p><p>To be successful with these initiatives, the in-person dealer experience, and the digital experience must be comparable across all platforms. Brands must evaluate how their connections with customers, dealers, suppliers, and vendors may help improve the whole automotive ownership experience for the growing population of digital natives.</p><h2 id="examples-of-digital-transformation-in-the-automotive-industry">Examples of digital transformation in the automotive industry<br/></h2><p>The automobile industry includes numerous remarkable examples of digital transformation, spanning from product innovation to operational efficiencies to changes in how the firm communicates with its consumers directly. The following are a few examples of how automakers have embraced digital transformation:<br/></p><ul><li>Mercedes-Benz and Circular collaborated to build an environmental monitoring system for the supply chain of battery cell manufacturers.</li><li>Oxbotica, a company that develops software for self-driving cars, has partnered with Cisco to showcase an open roaming platform that enables autonomous fleets to transfer vast amounts of data effectively while on the road.</li><li>BMW's Regensburg plant achieved exceptional benefits due to an IoT infrastructure. It enables them to cut deployment time and quality control worries in half.</li><li>Automotive manufacturers and software developers collaborated to develop augmented reality systems that aid technicians in identifying damaged or broken components. MARTA is a method that enables technicians to work more efficiently.</li><li>Automobile paint and supplies have been readily available in brick-and-mortar establishments for an extended period. PBE Jobbers Warehouse, a distributor of automotive body equipment, has integrated e-commerce, customer relationship management (CRM), and enterprise resource planning (ERP) systems.</li></ul><h2 id="the-automobile-industrys-evolution-and-its-impact-on-customer-service">The automobile industry's evolution and its impact on customer service<br/></h2><p>Numerous facets of vehicle purchase developed during the twentieth century and have continued to expand to the current day. While both dealers and customers utilize eCommerce to offer new vehicles, the traditional purchasing procedure is more critical to both sides. Additionally, integrating digital instruments such as iPads into showrooms has improved customer service significantly.</p><p>As the world evolves in 2023, clients of all sorts will become increasingly willing to go online. Whether to consumers or businesses, you may communicate with customers via social media or an app if you sell online. This trend has the potential to accelerate in the coming years.</p><p>Autos will have a unique digital and integrated supply chain within the next two to five years. Developing an intelligent and digital supply chain is critical for all stakeholders in the business.</p><p>Further, product designers have been compelled to reconsider their designs in light of the COVID outbreak's growing problems. Production is being slowed down by issues such as a chip shortage. Remote monitoring and control have increased in popularity, as has the necessity for additional reporting tools. On the other side, automobile manufacturers are happy that the plague has gone, resulting in increased income as more people drive instead of flying.</p><p>In addition, automobile manufacturers are expected to raise their digital expenditure by up to 24 percent over several years as they contend with unprecedented competition and new product needs like electrification.</p><p>Businesses must constantly stay one step ahead of the competition to retain their clientele in today's environment. They must first assess their present and long-term technology requirements and then engage with the appropriate technology provider to assist them in accomplishing those goals. Additionally, they must enhance internal processes, retain and increase alliances, and decrease costs.</p><h2 id="to-summarize">To summarize<br/></h2><p>At the time, more collaboration between vehicle solution suppliers and the automotive sector was critical. Digital transformation is required at every stage of an organization's life cycle. In the long run, the solutions outlined above will benefit all parties, including manufacturers, suppliers, employees, and customers.</p><p>Consumer items from other industries are already being influenced by IoT, AI, and other upcoming technologies in 2022, which should be surprising and exciting. These advancements also affect the automotive industry's digital transformation.</p>]]></content:encoded></item><item><title><![CDATA[Language-Learning App Development Features in 2022]]></title><description><![CDATA[This article will reveal the benefits and the features of language learning apps that you will need to create an app loved by users.]]></description><link>https://blog.shahednasser.com/language-learning-app-development-features-in-2022/</link><guid isPermaLink="false">Ghost__Post__61f7d45460a9ab05cc5e686a</guid><category><![CDATA[Business]]></category><dc:creator><![CDATA[Ava Miller]]></dc:creator><pubDate>Mon, 31 Jan 2022 12:27:17 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/214fe73a0031e926e09bb564bf6245c8/-Language-Learning-App-Development-Features-in-2022.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/214fe73a0031e926e09bb564bf6245c8/-Language-Learning-App-Development-Features-in-2022.jpg" alt="Language-Learning App Development Features in 2022"/><p>One of the most common aspirations is the urge to learn a new language. But once you started searching for courses or where to learn, you came across some barriers in time and cost. It probably seemed like an uphill climb to learn a new language. </p><p>To solve these challenges, entrepreneurs have ventured into language learning app development. But to do this, they need to learn <a href="https://www.aimprosoft.com/blog/how-to-build-a-language-learning-app/">how to create a language learning app</a> to capitalize on the opportunity. </p><p>The top language learning apps are great examples of what you will need to build a language learning app. These include Duolingo, Mondly, and Babble. </p><p>This article will reveal the benefits and the features of language learning apps that you will need to create an app loved by users. <br/></p><h2 id="benefits-of-language-learning-apps">Benefits of Language Learning Apps</h2><h3 id="convenience"><strong>Convenience</strong></h3><p>You want to learn a language, but the closest teachers and schools are far away. Language learning apps bring the teacher and class to your home, so you do not have to move anywhere. </p><p>As long as you have a PC or smart device with an internet connection, you can access language learning apps at your convenience. Furthermore, you can access them anytime you want to learn, even on your bathroom break. </p><h3 id="multiple-languages"><strong>Multiple Languages</strong></h3><p>Language learning apps bring several languages to your doorstep. Most language learning physical schools are specialized in one language, but apps usually have various languages such as French, German, Spanish, Greek, and more. </p><p>You can learn more than one language simultaneously on the same app while keeping track of your level. </p><h3 id="custom-levels"><strong>Custom Levels</strong></h3><p>You may have learned some basic French while at school and would like to start a bit higher up on the learning curve. With language learning apps, you can choose to begin at a beginner, intermediate or advanced level. </p><h3 id="progress-tracker"><strong>Progress Tracker</strong></h3><p>It is easy for us to forget the last thing we learned. Language learning apps keep track of that on your behalf and provide revisions to remind you of what you last learned. </p><p>Once you have revised and feel confident, you can move to the next level. </p><h2 id="features-for-language-learning-app-development">Features for Language Learning App Development</h2><p>Top learning language apps have incorporated features that make their user experience valuable. Here are some of the features of language learning apps you will need in yours.</p><h3 id="registration"><strong>Registration</strong></h3><p>You need an authorization system for users to provide their details. These include name, email, and contact. It is even better for your language learning app to have a registration process linked to social media platforms such as Facebook or Instagram. </p><h3 id="dashboard"><strong>Dashboard</strong></h3><p>The dashboard helps you keep track of your achievements and add tools to assist your language learning journey. You will know what level and lessons you have completed through your dashboard. </p><p>Users should track achievements such as rewards, bonuses, gems, and crowns that they can redeem within the app for prizes. </p><h3 id="illustration"><strong>Illustration</strong></h3><p>Images or pictures of vocabulary words can aid learning. A great language learning app should incorporate pictures that illustrate the content of sentences to help the user easily retain and recall information. </p><h3 id="online-community"><strong>Online Community</strong></h3><p>Most learners love to feel like they have comrades on their learning journey. Online communities help share their challenges, tips and tricks, and suggestions to make the app better. </p><p>Online communities encourage users through sharing in the progress and achievements of others through the language learning app. </p><h3 id="health"><strong>Health</strong></h3><p>You will make mistakes along with your language learning. The more mistakes you make, the more your health reduces. The purpose of this is to encourage users to take their learning seriously to progress to the next level. </p><h2 id="conclusion">Conclusion</h2><p>Language learning app development is essential for entrepreneurs trying to create an app that meets customer requirements. To get it right, you must include features that add value to the customer, such as registration, illustrations, and health, to make the user experience interesting and engaging. </p><p>You do not need to reinvent the wheel to be successful. You only need to learn from the best and tweak a few things to stand out.</p>]]></content:encoded></item><item><title><![CDATA[Can Java Be Used for eCommerce?]]></title><description><![CDATA[In this blog post, we will explore whether Java can be used for eCommerce.]]></description><link>https://blog.shahednasser.com/can-java-be-used-for-ecommerce/</link><guid isPermaLink="false">Ghost__Post__61e977bb6e875c05c40940bb</guid><category><![CDATA[Java]]></category><dc:creator><![CDATA[Chatty Garrate]]></dc:creator><pubDate>Mon, 24 Jan 2022 13:00:26 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/48a500d0da5870aa1b5100794e816e07/Can-Java-Be-Used-for-eCommerce.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/48a500d0da5870aa1b5100794e816e07/Can-Java-Be-Used-for-eCommerce.png" alt="Can Java Be Used for eCommerce?"/><p>Java is a versatile programming language that can be used for a variety of purposes. In this blog post, we will explore whether Java can be used for eCommerce. While it may not be the best option for every business, it does have some advantages that could make it a good choice for some companies.</p><p>Let's take a closer look at Java and see what it has to offer!</p><h2 id="still-going-strong-after-26-years">Still Going Strong After 26 Years</h2><p>Java is a powerful programming language that offers many advantages for businesses. It is a high-level, object-oriented programming language that is relatively easy to learn and use—making it an excellent language to learn<a href="https://junilearning.com/"> coding for beginners</a>.</p><p>Java is also a platform-independent language, which means it can be used on any computer system without having to worry about compatibility issues. It is fast, versatile, and scalable, making it an especially good choice for large-scale applications.</p><p>No wonder, then, that 90% of companies in the Fortune500 continue to employ Java in their operations. Of course, a sizeable chunk of this can be attributed to familiarity and legacy code, but the language is undeniably being used in more modern setups as well.</p><p>Java has been around for over 26 years and it is still going strong. This shows that it is a language that businesses can rely on. It also means that you will be able to find developers who are familiar with Java if you need help with your project.</p><p>As a small- to medium-sized eCommerce business, this bodes well as you'd want to choose a language that has staying power to make the most out of your investment.</p><p>Java also has a strong community behind it, which means that there is plenty of support available if you need it. Its large ecosystem offers plenty of options for eCommerce businesses. The vast number of Java frameworks available, as well as third-party libraries and tools, means that you will be able to find everything you need to create your eCommerce application without breaking the bank.</p><h2 id="some-limitations-of-java">Some Limitations of Java</h2><p>Although Java makes sense for a wide swathe of businesses, it does have some limitations.</p><p>Firstly, Java has high memory and processing requirements, which can lead to increased hardware costs.</p><p>Java also doesn't give you control over garbage collection, which can lead to performance bottlenecks that need to be addressed.</p><p>Finally, Java's complex code architecture can make it difficult for novice programmers to get started. This could lead to longer development times and higher costs if you're not careful.</p><p>All in all, Java is a great choice for businesses looking for a reliable and versatile programming language that can be used for eCommerce. While it does have some limitations, these can be overcome with careful planning and execution. As long as you're aware of what to expect, Java can be an excellent option for your eCommerce business.</p><h2 id="does-java-make-sense-for-your-ecommerce-business">Does Java Make Sense for Your eCommerce Business?</h2><p>Java is a strong contender for businesses looking for a programming language to use for eCommerce. But does it make sense for your specific business?</p><p>To answer that question, you'll need to consider the specific needs of your company. Java offers many advantages, including its platform independence, scalability, and large community.</p><p>However, as we noted above, Java's limitations might make it a poor choice for some businesses.</p><p>Let's break down some of the key factors you have to consider before using Java to develop your eCommerce application:</p><h3 id="memory-and-processing-requirements">Memory and processing requirements</h3><p>Java requires a lot of memory and processing power, which could lead to increased hardware costs. The near-infinite scalability offered by Java that makes it so favored among Fortune500 companies comes with a price—make sure this investment is right for your business.</p><p>One of the biggest reasons for Java's higher memory usage is its virtual machine (VM) platform, which allows the language to run on any computer system without having to worry about compatibility issues. If you're not sure if your business needs this level of flexibility, you may want to opt for<a href="https://blog.shahednasser.com/7-javascript-color-libraries-and-which-should-you-choose/"> JavaScript</a>, which is more of a lighter scripting language.</p><h3 id="garbage-collection">Garbage collection</h3><p>Java's automatic garbage system comes with its proprietary memory management system. Businesses that need a greater degree of control over your eCommerce site's garbage collection might want to look for an alternative programming language.</p><h3 id="access-to-expert-programmers">Access to expert programmers</h3><p>Java's complex code architecture can be difficult for novice programmers to get started with, resulting in longer development times and higher costs. If you don't have the resources to spare, another language might be a better choice.</p><p>If you live or work near areas with a high concentration of Java developers, you're in luck. The<a href="https://andela.com/java-architects/"> benefits of having Java developers</a> nearby are many—they can help shorten your development time, offer after-sales support and advice, and more. However, if you don't have this luxury, you can always outsource your development needs to a remote company.</p><h2 id="conclusion">Conclusion</h2><p>In the end, it's important to weigh all of Java's pros and cons before making a decision. The language offers many advantages for businesses looking to create an eCommerce application, but make sure that its limitations don't outweigh its benefits for your specific company. With careful planning, Java can be an excellent option for your eCommerce business.</p>]]></content:encoded></item><item><title><![CDATA[Create PDF in Laravel Tutorial]]></title><description><![CDATA[In this tutorial, you'll learn how to create PDF files using Laravel and mPDF.]]></description><link>https://blog.shahednasser.com/create-pdf-in-laravel-tutorial/</link><guid isPermaLink="false">Ghost__Post__61e1abbe61dbd80628bf9c3c</guid><category><![CDATA[Laravel]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 19 Jan 2022 08:48:05 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/73eecbeb674f24af57f306eecd68e86e/Create-PDF-with-Laravel-Tutorial-7.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/73eecbeb674f24af57f306eecd68e86e/Create-PDF-with-Laravel-Tutorial-7.png" alt="Create PDF in Laravel Tutorial"/><p><a href="https://laravel.com">Laravel</a> is one of the most popular web development frameworks. It allows you to create fast, modern, and scalable websites for almost every use case.</p><p>In this tutorial, you'll learn how to create PDF files using Laravel and <a href="https://mpdf.github.io">mPDF</a>. You'll create a website that shows the user a rich text editor where they can add whatever content they want, then transform that content into a PDF file.</p><p>You can find the full code for the tutorial at <a href="https://github.com/shahednasser/laravel-pdf-tutorial">this GitHub repository</a>.</p><h2 id="prerequisites">Prerequisites</h2><p>To follow along with this tutorial, you need to have <a href="https://www.php.net">PHP</a> installed. As this tutorial uses Laravel 8 and mPDF v8 (the latest versions at the time of writing), you should have a 7.3 or 7.4 PHP version, as mPDF only supports up to version 7.4.</p><p>You also need to have <a href="https://getcomposer.org/download/">Composer</a> installed.</p><h2 id="project-setup">Project Setup</h2><p>In this section, you'll set up a Laravel project. Open your terminal and run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">composer</span> create-project laravel/laravel laravel-pdf-tutorial</code></pre></div><p>This will create the directory <code class="language-text">laravel-pdf-tutorial</code> with the Laravel installation inside.</p><p>Once it's done, change to that directory and install mPDF to be used later:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">composer</span> require mpdf/mpdf</code></pre></div><h2 id="create-page">Create Page</h2><p>As mentioned, you'll create a web page that will show the user a text editor that they can use to enter any content they want. It'll also show some configurations for creating the PDF file.</p><p>Create the file <code class="language-text">resources/views/home.blade.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span><span class="token operator">!</span><span class="token constant">DOCTYPE</span> html<span class="token operator">></span> <span class="token operator"><</span>html lang<span class="token operator">=</span><span class="token string double-quoted-string">"en"</span><span class="token operator">></span> <span class="token operator"><</span>head<span class="token operator">></span> <span class="token operator"><</span>meta charset<span class="token operator">=</span><span class="token string double-quoted-string">"UTF-8"</span><span class="token operator">></span> <span class="token operator"><</span>meta name<span class="token operator">=</span><span class="token string double-quoted-string">"viewport"</span> content<span class="token operator">=</span><span class="token string double-quoted-string">"width=device-width, initial-scale=1.0"</span><span class="token operator">></span> <span class="token operator"><</span>meta http<span class="token operator">-</span>equiv<span class="token operator">=</span><span class="token string double-quoted-string">"X-UA-Compatible"</span> content<span class="token operator">=</span><span class="token string double-quoted-string">"ie=edge"</span><span class="token operator">></span> <span class="token operator"><</span>title<span class="token operator">></span><span class="token constant">PDF</span> Maker<span class="token operator"><</span><span class="token operator">/</span>title<span class="token operator">></span> <span class="token operator"><</span>link href<span class="token operator">=</span><span class="token string double-quoted-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"</span> rel<span class="token operator">=</span><span class="token string double-quoted-string">"stylesheet"</span> integrity<span class="token operator">=</span><span class="token string double-quoted-string">"sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"</span> crossorigin<span class="token operator">=</span><span class="token string double-quoted-string">"anonymous"</span><span class="token operator">></span> <span class="token operator"><</span>script src<span class="token operator">=</span><span class="token string double-quoted-string">"https://cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js"</span> referrerpolicy<span class="token operator">=</span><span class="token string double-quoted-string">"origin"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span> <span class="token operator"><</span>script<span class="token operator">></span> tinymce<span class="token operator">.</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">{</span> selector<span class="token punctuation">:</span> <span class="token string single-quoted-string">'.editor'</span><span class="token punctuation">,</span> <span class="token argument-name">toolbar</span><span class="token punctuation">:</span> <span class="token string single-quoted-string">'styleselect | alignleft aligncenter alignright | bold italic underline strikethrough | image | bullist numlist | table'</span><span class="token punctuation">,</span> <span class="token argument-name">plugins</span><span class="token punctuation">:</span> <span class="token string single-quoted-string">'image lists table'</span><span class="token punctuation">,</span> <span class="token argument-name">automatic_uploads</span><span class="token punctuation">:</span> <span class="token constant boolean">true</span><span class="token punctuation">,</span> <span class="token argument-name">file_picker_types</span><span class="token punctuation">:</span> <span class="token string single-quoted-string">'image'</span><span class="token punctuation">,</span> <span class="token argument-name">file_picker_callback</span><span class="token punctuation">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span>cb<span class="token punctuation">,</span> value<span class="token punctuation">,</span> meta<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> input <span class="token operator">=</span> document<span class="token operator">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'input'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> input<span class="token operator">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'type'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'file'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> input<span class="token operator">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'accept'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'image/*'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> input<span class="token operator">.</span>onchange <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> file <span class="token operator">=</span> this<span class="token operator">.</span>files<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">var</span> reader <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileReader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> reader<span class="token operator">.</span>onload <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> id <span class="token operator">=</span> <span class="token string single-quoted-string">'blobid'</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> blobCache <span class="token operator">=</span> tinymce<span class="token operator">.</span>activeEditor<span class="token operator">.</span>editorUpload<span class="token operator">.</span>blobCache<span class="token punctuation">;</span> <span class="token keyword">var</span> base64 <span class="token operator">=</span> reader<span class="token operator">.</span>result<span class="token operator">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string single-quoted-string">','</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">var</span> blobInfo <span class="token operator">=</span> blobCache<span class="token operator">.</span><span class="token function">create</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span> file<span class="token punctuation">,</span> base64<span class="token punctuation">)</span><span class="token punctuation">;</span> blobCache<span class="token operator">.</span><span class="token function">add</span><span class="token punctuation">(</span>blobInfo<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">cb</span><span class="token punctuation">(</span>blobInfo<span class="token operator">.</span><span class="token function">blobUri</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> title<span class="token punctuation">:</span> file<span class="token operator">.</span>name <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> reader<span class="token operator">.</span><span class="token function">readAsDataURL</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> input<span class="token operator">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>head<span class="token operator">></span> <span class="token operator"><</span>body<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"container my-4 mx-auto"</span><span class="token operator">></span> <span class="token operator"><</span>form action<span class="token operator">=</span><span class="token string double-quoted-string">"#"</span> method<span class="token operator">=</span><span class="token string double-quoted-string">"POST"</span><span class="token operator">></span> @csrf <span class="token operator"><</span>h1<span class="token operator">></span><span class="token constant">PDF</span> Maker<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>h2<span class="token operator">></span>Configurations<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"name"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-label"</span><span class="token operator">></span><span class="token constant">PDF</span> Name<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"text"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"name"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"name"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"header"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-label"</span><span class="token operator">></span>Header<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>textarea name<span class="token operator">=</span><span class="token string double-quoted-string">"header"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"header"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"editor"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>textarea<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"footer"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-label"</span><span class="token operator">></span>Footer<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>div id<span class="token operator">=</span><span class="token string double-quoted-string">"footerHelp"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-text"</span><span class="token operator">></span>You can <span class="token keyword">use</span> <span class="token punctuation">{</span><span class="token constant">PAGENO</span><span class="token punctuation">}</span> to add page numbering to all pages<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>textarea name<span class="token operator">=</span><span class="token string double-quoted-string">"footer"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"footer"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"editor"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>textarea<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-check mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>input <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-check-input"</span> type<span class="token operator">=</span><span class="token string double-quoted-string">"checkbox"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"show_toc"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"show_toc"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-check-label"</span> <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"show_toc"</span><span class="token operator">></span> Show Table of Content<span class="token operator">?</span> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>h2<span class="token operator">></span>Content<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span> <span class="token operator"><</span>textarea name<span class="token operator">=</span><span class="token string double-quoted-string">"content"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"content"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"editor"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>textarea<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"text-center"</span><span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string double-quoted-string">"button"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"btn btn-primary"</span><span class="token operator">></span>Create<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>script src<span class="token operator">=</span><span class="token string double-quoted-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"</span> integrity<span class="token operator">=</span><span class="token string double-quoted-string">"sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"</span> crossorigin<span class="token operator">=</span><span class="token string double-quoted-string">"anonymous"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>body<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>html<span class="token operator">></span></code></pre></div><p>In this code, we show a form with configurations and a text editor for the content. We use <a href="https://getbootstrap.com">Bootstrap</a> for easy styling, and <a href="https://www.tiny.cloud/docs/quick-start/">TinyMCE</a> to easily insert an editor in our form. With TinyMCE, we also add an image picker based on <a href="https://www.tiny.cloud/docs/demo/file-picker/">this example</a> from their documentation.</p><p>For the configurations, we show a field to enter the name of the PDF, a text editor to style the header, a text editor to style the footer, and a checkbox to enable or disable the table of content.</p><p>Next, in <code class="language-text">routes/web.php</code> change the route for the home page to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Now, run the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan serve</code></pre></div><p>If you open the website now at <code class="language-text">localhost:8000</code> (by default), you'll see the form we just created.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-18-at-6.33.29-PM.png" class="kg-image" alt="Create PDF in Laravel Tutorial" loading="lazy" width="2000" height="1141" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-18-at-6.33.29-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-18-at-6.33.29-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-18-at-6.33.29-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2022/01/Screen-Shot-2022-01-18-at-6.33.29-PM.png 2400w" sizes="(min-width: 720px) 720px"><figcaption>PDF Maker Home Page</figcaption></img></figure><p>If you see a notice on the editors regarding an API key, this is because we're using the CDN without an API key. You can obtain an API key by signing up to <a href="https://www.tiny.cloud/auth/signup/">Tiny Cloud</a>, or by <a href="https://www.tiny.cloud/get-tiny/self-hosted/">downloading and self-hosting</a> the TinyMCE library.</p><p>Notice that for the footer, we add a note that to add a page number to all pages we can use the placeholder <code class="language-text">{PAGENO}</code>. This can be added to the header or footer.</p><h2 id="create-pdf">Create PDF</h2><p>In this section, you'll create the controller that will handle the form submission and create the PDF.</p><p>In your terminal, run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan make:controller PdfController</code></pre></div><p>Then, open the controller at <code class="language-text">app/Http/Controllers/PdfController.php</code> and place the following method inside the class:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">createPdf</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//validate request</span> <span class="token class-name static-context">Validator</span><span class="token operator">::</span><span class="token function">validate</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'name'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'required|string|min:1'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'content'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'required|string|min:1'</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//create PDF</span> <span class="token variable">$mpdf</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Mpdf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$header</span> <span class="token operator">=</span> <span class="token function">trim</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'header'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$footer</span> <span class="token operator">=</span> <span class="token function">trim</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'footer'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">strlen</span><span class="token punctuation">(</span><span class="token variable">$header</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$mpdf</span><span class="token operator">-></span><span class="token function">SetHTMLHeader</span><span class="token punctuation">(</span><span class="token variable">$header</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">strlen</span><span class="token punctuation">(</span><span class="token variable">$footer</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$mpdf</span><span class="token operator">-></span><span class="token function">SetHTMLFooter</span><span class="token punctuation">(</span><span class="token variable">$footer</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'show_toc'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$mpdf</span><span class="token operator">-></span><span class="token property">h2toc</span> <span class="token operator">=</span> <span class="token keyword">array</span><span class="token punctuation">(</span> <span class="token string single-quoted-string">'H1'</span> <span class="token operator">=></span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'H2'</span> <span class="token operator">=></span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'H3'</span> <span class="token operator">=></span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'H4'</span> <span class="token operator">=></span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'H5'</span> <span class="token operator">=></span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'H6'</span> <span class="token operator">=></span> <span class="token number">5</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$mpdf</span><span class="token operator">-></span><span class="token function">TOCpagebreak</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//write content</span> <span class="token variable">$mpdf</span><span class="token operator">-></span><span class="token function">WriteHTML</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//return the PDF for download</span> <span class="token keyword">return</span> <span class="token variable">$mpdf</span><span class="token operator">-></span><span class="token function">Output</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'name'</span><span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'.pdf'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Destination</span><span class="token operator">::</span><span class="token constant">DOWNLOAD</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Make sure to also add the necessary imports at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Validator</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Mpdf<span class="token punctuation">\</span>Mpdf</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Mpdf<span class="token punctuation">\</span>Output<span class="token punctuation">\</span>Destination</span><span class="token punctuation">;</span></code></pre></div><p>First, you validate the request using Laravel's Validate Facade. You can learn more about Laravel's Validation in <a href="https://blog.shahednasser.com/beginners-guide-to-validation-in-laravel">this tutorial</a>.</p><p>After validating the request parameters, you create a new instance of <code class="language-text">Mpdf</code>. You can pass <a href="https://mpdf.github.io/configuration/configuration-v7-x.html">a lot of configurations to mPDF's constructor</a> which allows you to set things like the font used or the text direction.</p><p>Next, you retrieve the values for Header and Footer entered by the user. If there are any entered, you set the Header with <code class="language-text">SetHTMLHeader</code> and Footer with <code class="language-text">SetHTMLFooter</code>. This will set the header and footer on all pages.</p><p>Then, you check if <code class="language-text">show_toc</code> was checked. If it was, you add a Table of Content at the beginning of the PDF using <code class="language-text">TOCpagebreak</code>. You also use the mPDF instance's <code class="language-text">h2toc</code> parameter to define the hierarchy that should be used in the table of content. This makes it easier for <code class="language-text">Mpdf</code> to generate the table of content from the PDF's content.</p><p>Next, you set the content of the PDF using <code class="language-text">WriteHTML</code>. You will write the <code class="language-text">content</code> entered by the user as is. Since TinyMCE sends the content to the server as HTML, the content should look exactly the same in the editor as it is in the PDF.</p><p>Finally, you return the PDF for download using the <code class="language-text">Output</code> method. This method receives as a first parameter the file name, and as a second parameter the return type. Its values can be <code class="language-text">I</code> for inline (default behavior), <code class="language-text">D</code> for download which will force download in the browser, <code class="language-text">F</code> for file which should be used when storing the created file, and <code class="language-text">S</code> for String Return which should be used when the PDF should be returned as a string.</p><p>In this case, you use <code class="language-text">D</code> which will create the PDF and trigger the download automatically.</p><p>Now that the controller's method is finished, add the new route in <code class="language-text">routes/web.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/create'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name class-name-fully-qualified static-context">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>PdfController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'createPdf'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>And change the <code class="language-text">action</code> attribute of the form in <code class="language-text">resources/views/home.blade.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>form action<span class="token operator">=</span><span class="token string double-quoted-string">"/create"</span> method<span class="token operator">=</span><span class="token string double-quoted-string">"POST"</span><span class="token operator">></span></code></pre></div><p>That's all! Now, open the home page again and enter all the content you want. You can enter images, tables, lists, and more. Once you're done, click on Create, and the PDF will be generated and downloaded. Notice how the content is exactly similar to how it looks in the editor.</p><h2 id="bonus-adding-stylesheets">Bonus: Adding Stylesheets</h2><p>mPDF allows you to add styling to your PDF document. You can pass it as a stylesheet as follows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token variable">$stylesheet</span> <span class="token operator">=</span> <span class="token string double-quoted-string">"h1 { color: red; }"</span><span class="token punctuation">;</span> <span class="token variable">$mpdf</span><span class="token operator">-></span><span class="token function">WriteHTML</span><span class="token punctuation">(</span><span class="token variable">$stylesheet</span><span class="token punctuation">,</span><span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Mpdf<span class="token punctuation">\</span>HTMLParserMode</span><span class="token operator">::</span><span class="token constant">HEADER_CSS</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h2 id="conclusion">Conclusion</h2><p>There are a lot of use cases where you would need to create a PDF file. In Larave, you can easily do that using mPDF. There are so many functionalities and things you can do with mPDF so be sure to check out <a href="https://mpdf.github.io/getting-started/creating-your-first-file.html">their documentation</a>.</p>]]></content:encoded></item><item><title><![CDATA[Turn a Shopify backend open-source and headless in less than 10 minutes]]></title><description><![CDATA[In this article, I will show you how to migrate all of your products and collections from a Shopify backend to Medusa in less than 10 minutes.]]></description><link>https://dev.to/medusajs/turn-a-shopify-backend-open-source-and-headless-in-less-than-10-minutes-2g8m</link><guid isPermaLink="false">Ghost__Post__61e43f6761dbd80628bf9c6e</guid><category><![CDATA[Javascript]]></category><category><![CDATA[Reviews]]></category><category><![CDATA[eCommerce]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 17 Jan 2022 09:00:00 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/8237dc0ebed05de278eb51f3d3519622/medusa-shopify.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/8237dc0ebed05de278eb51f3d3519622/medusa-shopify.png" alt="Turn a Shopify backend open-source and headless in less than 10 minutes"/><p>In this article, I will show you how to migrate <em>all</em> of your products and collections from a Shopify backend to an open-source headless commerce backend, <a href="https://github.com/medusajs/medusa">Medusa</a>, in less than 10 minutes.</p><p>Medusa is an open-source Shopify alternative giving you all of the necessary primitives to build and operate a webshop. Below, I will first walk you through the features of Medusa. Then I’ll move on to a guide on how to use the plugin to quickly import your Shopify products and collections into Medusa. Finally, I’ll go into a bit more depth on some of the reasons why you should consider moving from Shopify to an open-source headless platform.</p><h2 id="why-use-medusa">Why Use Medusa</h2><p>As <a href="https://www.medusajs.com/">Medusa</a> is an open-source headless commerce platform, it allows you to completely customize and compose your stack to fit your needs. You’re not bound to a monolithic architecture where everything is tightly coupled. Some of the main benefits of this are:</p><ol><li>It gives you full flexibility to build any type of frontend(s) you may prefer - Medusa has starters in <a href="https://github.com/medusajs/nextjs-starter-medusa">Next.js</a> or <a href="https://github.com/medusajs/gatsby-starter-medusa">Gatsby</a> to set up a high-performing storefront out-of-the-box so you have a good starting point before starting to customize it to your needs. You can check out a demo of the starer <a href="https://start.medusajs.com/">here</a>.</li><li>The open-source nature lets you customize the core engine to cater to more advanced business cases and requirements that are often outside the scope of monolithic platforms. The code-base is meant to be extendible and customizable which you can feel from the very first time you try to add own functionality to it.</li><li>Medusa's plugin architecture makes it intuitive and easy to manage your integrations, switch providers and grow with ease. It even comes with a lot of pre-made integrations to CMSs, payments, shipping, analytics, marketing and more. You can check them all out <a href="https://github.com/medusajs/medusa/tree/master/packages">here</a>.</li><li>Also on features, Medusa provides a few different additions that makes it stand out such as the option to define regional currency, shipping and payment options which is one of the more known issues for business owners running on Shopify and wants to sell across markets. Another example is return, exchange and claim handling which are all fully-automated processes in Medusa that makes it easy to use for customer service personnel.</li></ol><p>There are therefore many reasons to migrate from a monolithic solution like Shopify to a headless open source solution. In the next session, we will walk through how easy this type of migration process can be.</p><h2 id="how-to-migrate-data-from-shopify-to-medusa">How to Migrate Data from Shopify to Medusa</h2><p>In this section of the article, you’ll learn how to use Medusa’s plugin to import your products and collections from Shopify into Medusa.</p><p>This section assumes you already have a Shopify store up and running with products to import. It also assumes you already have Medusa set up and ready to use. If you don’t, then you should check out <a href="https://dev.to/medusajs/get-started-with-medusa-the-open-source-alternative-to-shopify-305j">this tutorial on how you can set up and run Medusa</a>.</p><p>In my case, I have 30 products in my Shopify store, each having many variants and attributes.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kE5_98pe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/300bdvqcbijncqiey56z.png" class="kg-image" alt="Turn a Shopify backend open-source and headless in less than 10 minutes" loading="lazy"/></figure><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lc83QBQq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yqbkrpjqik5jzbz9shi3.png" class="kg-image" alt="Turn a Shopify backend open-source and headless in less than 10 minutes" loading="lazy"/></figure><h3 id="create-a-private-shopify-app">Create a Private Shopify App</h3><p>To be able to import the data from Shopify into Medusa, you need to create an App in your store with limited permissions. This will give you different types of keys to access the App and the data in the store.</p><p>Open your store’s dashboard. Then, choose <em>Apps</em> from the sidebar. Then, scroll down and click on <em>Manage private apps</em>.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G8qpQc6F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0jlrvewzvqalgmizuio0.png" class="kg-image" alt="Turn a Shopify backend open-source and headless in less than 10 minutes" loading="lazy"/></figure><p>If you haven’t enabled private apps previously, you’ll be asked to enable them first. click on <em>Enable private app development</em> to enable it.</p><p>After you have enable private app development, you’ll be able to create a private app. Click on <em>Create private app</em> to get started.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qUiLsIci--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dcvh7ttgilvxnhadhzoh.png" class="kg-image" alt="Turn a Shopify backend open-source and headless in less than 10 minutes" loading="lazy"/></figure><p>You’ll then need to enter your app’s name and your email. Then, scroll down to the Admin API section and click on <em>Show inactive Admin API permissions</em>. Scroll down to Products and choose Read Access from the dropdown. Medusa only needs to read products and collections.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--86Pt8xBN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4hcjlolm3xwrj1ghkfn3.png" class="kg-image" alt="Turn a Shopify backend open-source and headless in less than 10 minutes" loading="lazy"/></figure><p>Scroll down to the end of the page and click the <em>Save</em> button. Then, click <em>Create App</em> in the pop-up that shows up.</p><p>After you create the app, you’ll be able to see a set of keys such as API Key and Password. What you’ll need for the plugin is the password, so keep it available for the next step.</p><h3 id="add-medusa-source-shopify-to-your-medusa-store">Add medusa-source-shopify to your Medusa store</h3><p>You’ll now integrate the <a href="https://github.com/medusajs/medusa/tree/ec0f2df2854d497f49ce94f74636723f0c0e2e26/packages/medusa-source-shopify">Shopify plugin</a> into your Medusa server. To integrate the plugin, you need the following:</p><ol><li>The Shopify domain name and the password of the Shopify app you want to link to.</li><li>PostgreSQL database used with your Medusa server.</li></ol><p>At this point of the article, it’s assumed you have all of these requirements ready.</p><p>Open your terminal in your Medusa server installation and run the following command to install the plugin:<br/></p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm i medusa-source-shopify</code></pre></div><p>Then, in <code class="language-text">.env</code> add the following new variables:<br/></p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">SHOPIFY_DOMAIN= SHOPIFY_PASSWORD= </code></pre></div><p>Where <code class="language-text">SHOPIFY_DOMAIN</code> is the subdomain name of your Shopify store (for example, my store is shahednasser.myshopify.com, so the value would be shahednasser), and <code class="language-text">SHOPIFY_PASSWORD</code> is the password generated when you created the app earlier.</p><p>Then, open <code class="language-text">medusa-config.js</code> and add a new entry into the <code class="language-text">plugins</code> array:<br/></p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"> const plugins = [ ..., { resolve: 'medusa-source-shopify', options: { domain: process.env.SHOPIFY_DOMAIN, password: process.env.SHOPIFY_PASSWORD } } ]; </code></pre></div><p>This will add the Shopify plugin into your Medusa server and will pass the options for the domain and password from the environment variables you just added.</p><p>And that’s all you need to integrate Medusa with Shopify to import your data. All you need to do now is run your server:<br/></p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm start </code></pre></div><p>And the server will import all the products and collections from Shopify into your Medusa store. Your server will do that everytime you start it, so your products and collections will be automatically synced on server restart.</p><p>Your products and collections will be imported with pricing, variants, and all the attributes and details you had in your Shopify store.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G5bOpc_w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e5m1t857zaur5t8s389d.png" class="kg-image" alt="Turn a Shopify backend open-source and headless in less than 10 minutes" loading="lazy"/></figure><h2 id="why-migrate-from-shopify-to-an-open-source-backend">Why Migrate From Shopify to an Open Source backend</h2><p>According to <a href="https://trends.builtwith.com/shop/Shopify">BuiltWith</a>, there are over 3.7M live websites that use Shopify at the time of writing this. This makes Shopify one of the most used ecommerce platforms. Shopify is known to provide an easy experience for brands and businesses of any size to launch and operate their online business.</p><p>Although Shopify has a lot of advantages that make businesses and developers gravitate towards it, it all comes at the expense of <em>less ownership of the tech stack</em>. At first glance, especially for smaller businesses that are just looking to start a store as soon as possible, it may seem like an irrelevant detail.</p><p>However, any business that have expanded from a few sales a week to becoming a serious ecommerce business can tell how important it is to be able to fully own the tech stack behind your webshop. Owning your website’s codebase, and having the flexibility to change and reform it based on your growing business needs is an important detail that will come up as time passes by. Shifting integrations, opening up new markets, customizing the UX are just some of the areas in which developers encounter problems when scaling with a monolithic platforms.</p><p>In addition to the issues related to scaling, using an open-source solution means that the platform you’re using is free forever. Using Shopify comes at a high price that grows as you scale as it is often directly linked to your webshop revenue and transaction volume. This will add to the additional costs of creating and operating your system.</p><h2 id="conclusion">Conclusion</h2><p>Shopify is a powerful ecommerce platform that is used by millions of websites across the globe. Although it has a ton of great features, it has some disadvantages as well, most notably your tech stack ownership.</p><p>With ecommerce platforms like Medusa you can completely own your tech stack and have many of the features you like about Shopify into your own open-source store. Medusa even makes it easier by allowing you to import your data from Shopify into Medusa using this easy-to-use plugin.</p><p>Should you have any issues or questions related to Medusa, then feel free to reach out to the Medusa team via <a href="https://discord.gg/F87eGuwkTp">Discord</a>.</p>]]></content:encoded></item><item><title><![CDATA[7 JavaScript Color Libraries and Which Should You Choose]]></title><description><![CDATA[In this article, I'll share with you 7 JavaScript libraries that allow you to manipulate colors one way or another.]]></description><link>https://blog.shahednasser.com/7-javascript-color-libraries-and-which-should-you-choose/</link><guid isPermaLink="false">Ghost__Post__61d3153061dbd80628bf9acd</guid><category><![CDATA[JavaScript Libraries]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 10 Jan 2022 09:31:04 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/79af11ec1e4a52a445b5e850f1717a15/pawel-czerwinski-3k9PGKWt7ik-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/79af11ec1e4a52a445b5e850f1717a15/pawel-czerwinski-3k9PGKWt7ik-unsplash-2.jpg" alt="7 JavaScript Color Libraries and Which Should You Choose"/><p>When it comes to JavaScript, there's a ton of libraries that allow you to do basically almost anything. This will be the start of a new series of X JavaScript libraries to do something. This series will not just present libraries with a link and a brief description. This series will showcase the pros and cons of the libraries, and why you should consider one over the other.</p><p>To start us off, in this article I'll share with you 7 JavaScript libraries that allow you to manipulate colors one way or another.</p><h2 id="color2k"><a href="https://github.com/ricokahler/color2k">color2k</a></h2><p>Perhaps the biggest pro of color2k is its small size. At 2.9KB of size, color2k provides a set of functionalities that will allow you to parse and manipulate colors.</p><p>This library provides <a href="https://color2k.com">different useful methods</a> including converting colors like <a href="https://color2k.com/#to-hex">toHex</a> or <a href="https://color2k.com/#to-rgba">toRgba</a>, color manipulation like <a href="https://color2k.com/#darken">darken</a> or <a href="https://color2k.com/#mix">mix</a>, and more methods that allow you to parse colors.</p><p>This library is easy to use in your Node.js projects. All you need is to install it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i color2k</code></pre></div><p>Then import the methods you want to use:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> mix <span class="token punctuation">}</span> from color2k<span class="token punctuation">;</span></code></pre></div><p>The con of using this library is it can be limited when it comes to heavy color manipulation needs, which can be provided by other libraries.</p><h3 id="when-should-you-use-color2k">When Should You Use color2k?</h3><p>color2k is the perfect option if you're looking for a small and easy-to-use library that allows you to perform basic manipulation and parsing methods. If you're looking for a library to provide you with more options, then you should probably check out other libraries on this list.</p><h2 id="chromajs"><a href="https://github.com/gka/chroma.js">chroma.js</a></h2><p>If you're looking for a library that can give you more methods to manipulate and interpolate colors, then you should check out chroma.js. chroma.js, compared to color2k, provides a lot of methods to not only parse and convert colors but also perform a lot of operations on colors.</p><p>In addition, chroma.js provides methods like <a href="https://vis4.net/chromajs/#color-scales">scale</a> that allow you to represent a color scale between two or more colors. You can also retrieve a color scheme using the <a href="https://vis4.net/chromajs/#cubehelix">cubehelix</a> method. </p><p>Using this library is easy as well. You first need to install it in your Node.js project:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> chroma-js</code></pre></div><p>Then, import it where you need to use it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> chroma <span class="token keyword">from</span> <span class="token string">"chroma-js"</span><span class="token punctuation">;</span></code></pre></div><p>And you'll have access to all the methods you need.</p><p>The biggest con about chroma.js is the fact that it has probably the biggest size compared to other libraries on this list, with the size 13.5KB.</p><h3 id="when-should-you-use-chromajs">When Should You Use chroma.js?</h3><p>If you need a library that allows you to perform wide operations on colors then chroma.js is the one for you. If you, however, need to perform small operations, or you don't want to use a library with a relatively bigger size, then you should probably use another library from this list.</p><h2 id="color-thief"><a href="https://github.com/lokesh/color-thief">Color Thief</a></h2><p>Color Theif is different than other mentioned libraries in this article. Color Thief has only one purpose which is getting colors from a picture. You can use Color Thief either in your browser or in Node.</p><p>To use it in your browser you can either download from the repository the files under <code class="language-text">dist</code>. Alternatively, you can use their <a href="https://cdnjs.cloudflare.com/ajax/libs/color-thief/2.3.0/color-thief.umd.js">CDN</a>.</p><p>After you include the script to the file, you just need to create a new instance to use:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> colorThief <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ColorThief</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>To use it in Node, you just need to install it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i --save colorthief</code></pre></div><p>And then require it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> ColorThief <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'colorthief'</span><span class="token punctuation">)</span></code></pre></div><p>The library exposes 2 methods. The first is <code class="language-text">getColor</code> which allows you to retrieve the dominant color in an image. The second is <code class="language-text">getPalette</code> which allows you to retrieve all the colors in an image.</p><p>The biggest cron about this library is that it hasn't been updated since 2020. So, it doesn't seem like there will be ongoing bug or security fixes. You should consider that when using this library.</p><h3 id="when-should-you-use-color-thief">When Should You Use Color Thief?</h3><p>As Color Thief has only one purpose, it's pretty obvious that it should be used when you need that purpose. If you need a library to extract colors from an image, then Color Thief is a great option.</p><h2 id="color"><a href="https://github.com/Qix-/color">color</a></h2><p>color is another library that provides a wide set of methods to be used to manipulate and convert colors. One of color's pros is that it supports CSS string colors like <code class="language-text">rgb(255, 255, 255)</code>.</p><p>color has a wide set of color getters like <code class="language-text">red</code> which returns the <code class="language-text">red</code> value of a color or <code class="language-text">hsl</code> which retrieves the HSL value of a color. color also provides a wide set of manipulation methods like <code class="language-text">desaturate</code> and <code class="language-text">lighten</code>.</p><p>The installation and usage are easy. You can install <code class="language-text">color</code> with NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> color</code></pre></div><p>Then, require it where you need to use it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> Color <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'color'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>and you'll have access to all its methods.</p><p>color's manipulation and interpolation methods are not as many as chroma.js, but it has a smaller size (7.6KB).</p><h3 id="when-should-you-use-color">When Should You Use color?</h3><p>If you're looking for a color manipulation library that has more to offer than color2k and less size than chroma.js that can still satisfy your needs, then you should go for color.</p><h2 id="random-color"><a href="https://github.com/davidmerfield/randomColor">Random Color</a></h2><p>Random Color is another library with a single purpose. Using Random Color, you can generate (you guessed it) random colors. However, it's not just that. You can also specify the number of options like <code class="language-text">hue</code>, <code class="language-text">format</code>, and <code class="language-text">luminosity</code> to make the color generated not too random.</p><p>You can install this package from NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> randomcolor</code></pre></div><p>And require it where you need to use it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">var</span> randomColor <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'randomcolor'</span><span class="token punctuation">)</span></code></pre></div><p>Alternatively, you can use it in your browser using their <a href="https://cdnjs.cloudflare.com/ajax/libs/randomcolor/0.6.1/randomColor.min.js">CDN</a>.</p><p>This library exposes one function only which is the <code class="language-text">randomColor</code> function. This function receives optionally an options object.</p><h3 id="when-should-you-use-random-color">When Should You Use Random Color?</h3><p>As it's a single-purpose library with a tiny size (2.1KB), it's perfect for when all you need is to generate a random color.</p><h2 id="ac-colors"><a href="https://github.com/vinaypillai/ac-colors">ac-colors</a></h2><p>ac-colors is a library that provides methods to parse and convert colors. It also provides methods to generate random colors. Although it doesn't provide a lot of options like Random Color when generating colors, it provides different methods to generate color in a certain format like <a href="https://github.com/vinaypillai/ac-colors#colorrandomoftypeformatted">randomOfTypeFormatted</a>.</p><p>ac-colors can be used in the browser using their <a href="https://cdn.jsdelivr.net/npm/ac-colors@1/dist/ac-colors.min.js">CDN</a>.</p><p>Alternatively, you can install it with NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> ac-colors</code></pre></div><p>Then requiring it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> Color <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"ac-colors"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>There are many functions in the library that allow so many different types of conversions and parsing of colors, as well as functions to generate random colors.</p><h3 id="when-should-you-use-ac-colors">When Should You Use ac-colors?</h3><p>ac-colors combines a bunch of methods from different libraries mentioned in this list. It's also a small library (3KB). It doesn't however provide functions to manipulate colors. So, if you need a library to convert and parse colors as well as generate random colors, then it's a good candidate.</p><h2 id="tinycolor"><a href="https://github.com/bgrins/TinyColor">TinyColor</a></h2><p>TinyColor can be used in both your browser and Node. It's mostly a library that allows you to know more about colors, with functions like <code class="language-text">isLight</code>. However, it still provides color manipulation functions like <code class="language-text">brighten</code> and <code class="language-text">darken</code>. On top of all of that, it allows you to generate color palettes and random colors.</p><p>As mentioned earlier, you can <a href="https://raw.githubusercontent.com/bgrins/TinyColor/master/tinycolor.js">use TinyColor in the browser</a>.</p><p>Alternatively, you can install it with NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> tinycolor2</code></pre></div><p>and require it where you need it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">var</span> tinycolor <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"tinycolor2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>TinyColor is relatively small (5KB) with the number of functionalities it provides.</p><p>Something that should be considered when choosing TinyColor is that it hasn't been updated since April 2021. So, it doesn't seem like it will receive any bug or security fixes in the future.</p><h3 id="when-should-you-use-tinycolor">When Should You Use TinyColor?</h3><p>TinyColor is perfect for when you need the best of everything. As it provides a combination of most functionalities we saw in other libraries, it's a good option if you need a library for a variety of uses. TinyColor is also a good option if you're looking for a library to use in the browser (without NPM), as a lot of the mentioned libraries don't offer that.</p><p>It doesn't, however, provide a wide set of manipulation functionalities like chroma.js.</p><h2 id="conclusion">Conclusion</h2><p>In this article, I shared some of the good JavaScript libraries that will allow you to manipulate, parse, convert, or perform other operations on colors.</p><p>Be sure to check out upcoming part of the series where we take a look at other libraries for specific functionalities to help you decide when you should use what.</p>]]></content:encoded></item><item><title><![CDATA[CSS Grid Tutorial For Beginners]]></title><description><![CDATA[In this article, I'll go over the basics of CSS Grid for absolute beginners who are looking to grasp the concept to use it in their projects.]]></description><link>https://blog.shahednasser.com/css-grid-tutorial-for-beginners/</link><guid isPermaLink="false">Ghost__Post__61d2b40c61dbd80628bf99b1</guid><category><![CDATA[CSS]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 05 Jan 2022 13:38:06 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/06c4e4dcfc476f5d1cd13f3d737bf0ee/sharon-mccutcheon-_Y3IuVbPpmU-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/06c4e4dcfc476f5d1cd13f3d737bf0ee/sharon-mccutcheon-_Y3IuVbPpmU-unsplash-2.jpg" alt="CSS Grid Tutorial For Beginners"/><p>CSS Grid Layout is immensely helpful in dividing up elements or the content of a page in rows and columns. It allows you to split up an area between components and define their size, position, placement, and more.</p><p>In this article, I'll go over the basics of CSS Grid for absolute beginners who are looking to understand it and grasp the concept to use it in their projects.</p><h2 id="why-use-css-grid">Why Use CSS Grid</h2><p>CSS Grids allow you to place items in a container while maintaining their layout and positions. With the Grid Layout, you have more control over where should each item be, what its width is, and how it should be placed in a container.</p><p>Think of a webpage and how there's usually a navigation bar, a sidebar, and the content in the middle. A CSS Grid can help you achieve that sort of styling easily by dividing up the page into different sections where each element can take place in the specified section.</p><p>CSS Grids can also be used in elements in a webpage rather than the entire webpage. Let's say you have a gallery and you want the images in the gallery to be all of the same sizes. You also want a specific number of images per row. You can control all of that using a CSS Grid.</p><p>A lot of beginners find the concept of CSS Grid Layout to be confusing. This article will hopefully help you understand the different properties that come with CSS Grid and how you can use them.</p><h2 id="your-first-grid">Your First Grid</h2><p>Let's say we have the following HTML:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>container<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>red<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>green<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>blue<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre></div><p>We want to make the div with the class <code class="language-text">container</code> a grid where we can control the elements inside as explained earlier.</p><p>All we need to do is change the <code class="language-text">display</code> property of the class <code class="language-text">container</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.container</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will make the element with the class <code class="language-text">container</code> a grid element. If you test this out, you'll see that you can see nothing. The reason behind that is the <code class="language-text">p</code> elements in the <code class="language-text">.container</code> grid don't have any elements in them or width or height.</p><p>Add the following CSS:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.container p</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.red</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.green</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.blue</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will set the width and height of the <code class="language-text">p</code> elements to <code class="language-text">100px</code>. It will also give a different background color for each element.</p><p>If you check your grid now it should look something like this:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-10.40.24-AM.png" class="kg-image" alt="CSS Grid Tutorial For Beginners" loading="lazy" width="502" height="794"/></figure><p>This is your first grid! As you can see, there's nothing fancy here as we haven't yet used any grid properties to place the elements or control their size.</p><p>Instead of specifying the width and height of each element, you can also use <code class="language-text">grid-auto-rows</code> and <code class="language-text">grid-auto-columns</code> on the grid element to specify the default height and width of elements:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.container</span> <span class="token punctuation">{</span> ... <span class="token property">grid-auto-rows</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span> <span class="token property">grid-auto-columns</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><h2 id="elements-placements">Elements Placements</h2><p>Grids consist of rows and columns. You can have as many rows or columns as you want in a Grid, and you can assign your elements to certain placements in a grid.</p><h2 id="columns">Columns</h2><p>Let's say you want to place these 3 elements as just 3 items in a row. we can do that using the <code class="language-text">grid-template-columns</code> property.</p><p>This property takes an <code class="language-text">n</code> number of values, where <code class="language-text">n</code> is the number of columns you want in the grid and each value is the width of each column.</p><p>For example, if you want to have 3 columns in the grid each having their width as <code class="language-text">100px</code> you can use:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 100px 100px 100px<span class="token punctuation">;</span></code></pre></div><p>This will divide the grid into 3 columns, and each column will be <code class="language-text">100px</code>.</p><p>Let's say you want the second column to be 200px:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 100px 200px 100px<span class="token punctuation">;</span></code></pre></div><p>If you also don't have a specific value to apply you can use the value <code class="language-text">auto</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token property">grid-template-columns</span><span class="token punctuation">:</span> auto auto auto<span class="token punctuation">;</span></code></pre></div><p>Alternatively, instead of repeating the values, you can use the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/repeat()">repeat()</a> function:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>3<span class="token punctuation">,</span> auto<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>The <code class="language-text">repeat</code> CSS function takes the first parameter the number of times an expression should be repeated, and the second parameter the statement to repeat.</p><p>Let's go back to our example, we'll place our elements in 3 columns, each having an automatic width.</p><p>Change the properties of <code class="language-text">.container</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.container</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span> <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>3<span class="token punctuation">,</span> auto<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will ensure the grid has 3 c0lumns with each having their width set to <code class="language-text">auto</code>.</p><p>Next, remove the width property set on the <code class="language-text">p</code> elements from earlier. It should only have height now:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.container p</span> <span class="token punctuation">{</span> <span class="token property">height</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>If you check the grid now, it should have 3 elements with equal widths next to each other.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-10.56.04-AM.png" class="kg-image" alt="CSS Grid Tutorial For Beginners" loading="lazy" width="2000" height="300" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-03-at-10.56.04-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-03-at-10.56.04-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-03-at-10.56.04-AM.png 1600w, https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-10.56.04-AM.png 2042w" sizes="(min-width: 720px) 720px"/></figure><h3 id="gap-between-columns">Gap Between Columns</h3><p>In a lot of cases, you might not want columns to be right next to each other. To add a gap between columns, you can use the property <code class="language-text">grid-column-gap</code> which takes the length of the gap between the columns as a value.</p><p>Let's say we want to add a gap of <code class="language-text">5px</code> between our columns. Add the following property to <code class="language-text">.container</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token property">grid-column-gap</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span></code></pre></div><p>This will add a <code class="language-text">5px</code> space between the grid columns.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-10.59.03-AM.png" class="kg-image" alt="CSS Grid Tutorial For Beginners" loading="lazy" width="2000" height="259" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-03-at-10.59.03-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-03-at-10.59.03-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-03-at-10.59.03-AM.png 1600w, https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-10.59.03-AM.png 2040w" sizes="(min-width: 720px) 720px"/></figure><h3 id="placement-in-columns">Placement in Columns</h3><p>You can control the placement of items relative to columns using the <code class="language-text">grid-column-start</code> and <code class="language-text">grid-column-end</code> properties. These properties allow you to specify at which column an item in a grid should start, and/or at which column an item in a grid should end.</p><p>The value for <code class="language-text">grid-column-start</code> and <code class="language-text">grid-column-end</code> can be a number. In this case, it will specify the column to start at and the column to end before.</p><p>For example, if you want to specify that the <code class="language-text">.red</code> element should start in the beginning and end before the 3rd column you use the following properties:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.red</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span> <span class="token property">grid-column-start</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span> <span class="token property">grid-column-end</span><span class="token punctuation">:</span> 3<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Now, the <code class="language-text">.red</code> element will span 2 columns and the <code class="language-text">.blue</code> element will be pushed to the row below.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.04.33-AM.png" class="kg-image" alt="CSS Grid Tutorial For Beginners" loading="lazy" width="2000" height="516" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-03-at-11.04.33-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-03-at-11.04.33-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-03-at-11.04.33-AM.png 1600w, https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.04.33-AM.png 2038w" sizes="(min-width: 720px) 720px"/></figure><p>Alternatively, you can provide a value to <code class="language-text">grid-column-start</code> and <code class="language-text">grid-column-end</code> in the format <code class="language-text">span n</code>, where <code class="language-text">n</code> is the number of columns to span. This does not specify where exactly the column should start or end. Instead, it specifies that in its natural place it should take up <code class="language-text">n</code> columns.</p><p>If we want to apply the same example, we can use the following properties for <code class="language-text">.red</code> instead:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.red</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span> <span class="token property">grid-column-start</span><span class="token punctuation">:</span> span 2<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This means the element should span 2 columns. This will result in the same layout as shown previously.</p><p>These properties can be used to control the element placements even more. For example, now that the blue element is on its own row let's place it at the end of it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.blue</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span> <span class="token property">grid-column-start</span><span class="token punctuation">:</span> 3<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Now, instead of the blue element just being shifted down outside of our control, we specify exactly where it should be:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.09.59-AM.png" class="kg-image" alt="CSS Grid Tutorial For Beginners" loading="lazy" width="2000" height="573" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-03-at-11.09.59-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-03-at-11.09.59-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-03-at-11.09.59-AM.png 1600w, https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.09.59-AM.png 2040w" sizes="(min-width: 720px) 720px"/></figure><h2 id="rows">Rows</h2><p>You just learned how to place and size our elements in the grid's columns. Next, you'll learn how to do the same, but in rows.</p><p>To specify how many rows a grid has, you can use <code class="language-text">grid-template-rows</code>. Similar to columns, the <code class="language-text">grid-template-rows</code> takes <code class="language-text">n</code> values, where <code class="language-text">n</code> is the number of rows the grid will have and the value is the height of each row.</p><p>So, if you want to have 2 rows of <code class="language-text">100px</code> height you can use the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token property">grid-template-rows</span><span class="token punctuation">:</span> 100px 100px<span class="token punctuation">;</span></code></pre></div><p>Alternatively, you can use the <code class="language-text">repeat</code> function:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token property">grid-template-rows</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>2<span class="token punctuation">,</span> 100px<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This will create 2 rows each having 100px height.</p><p>Let's go back to our example. In this section, we want to have 2 columns and 2 rows. Change <code class="language-text">.container</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.container</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span> <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>2<span class="token punctuation">,</span> auto<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">grid-template-rows</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>2<span class="token punctuation">,</span> 100px<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">grid-column-gap</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will create 2 columns of <code class="language-text">auto</code> width and 2 rows of <code class="language-text">100px</code> height.</p><p>Next, reset the rest of the styles that we performed earlier:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.red</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.green</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.blue</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will just set the background color of each of the child elements. Notice that you don't need to set the height and width anymore of the elements as we're applying it using <code class="language-text">grid-template-columns</code> and <code class="language-text">grid-template-rows</code>.</p><p>If you check your grid now you should have 2 items in one row and an item on the second.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.19.42-AM.png" class="kg-image" alt="CSS Grid Tutorial For Beginners" loading="lazy" width="2000" height="429" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-03-at-11.19.42-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-03-at-11.19.42-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-03-at-11.19.42-AM.png 1600w, https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.19.42-AM.png 2034w" sizes="(min-width: 720px) 720px"/></figure><h3 id="gap-between-rows">Gap Between Rows</h3><p>In a lot of cases, you won't need the items in different rows right next to each other. You can add space between rows using <code class="language-text">grid-row-gap</code>.</p><p>Let's say we want to add a <code class="language-text">5px</code> gap between rows. Add the following property to the <code class="language-text">.container</code> class:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token property">grid-row-gap</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span></code></pre></div><p>This will add a <code class="language-text">5px</code> space between the rows in our grid.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.21.35-AM.png" class="kg-image" alt="CSS Grid Tutorial For Beginners" loading="lazy" width="2000" height="430" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-03-at-11.21.35-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-03-at-11.21.35-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-03-at-11.21.35-AM.png 1600w, https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.21.35-AM.png 2038w" sizes="(min-width: 720px) 720px"/></figure><h3 id="placement-in-rows">Placement in Rows</h3><p>You can use the grid layout to control the placement of elements in rows. To do that, you can use the properties <code class="language-text">grid-row-start</code> and <code class="language-text">grid-row-end</code>.</p><p>The value of <code class="language-text">grid-row-start</code> and <code class="language-text">grid-row-end</code> can be a number. The value of <code class="language-text">grid-row-start</code> will be the row the element should start on, and the value of <code class="language-text">grid-row-end</code> will be the row the element should end before.</p><p>For example, to make sure that the <code class="language-text">red</code> element spans 2 rows we can use the following properties:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.red</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span> <span class="token property">grid-row-start</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span> <span class="token property">grid-row-end</span><span class="token punctuation">:</span> 3<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.25.12-AM.png" class="kg-image" alt="CSS Grid Tutorial For Beginners" loading="lazy" width="2000" height="435" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-03-at-11.25.12-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-03-at-11.25.12-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-03-at-11.25.12-AM.png 1600w, https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.25.12-AM.png 2040w" sizes="(min-width: 720px) 720px"/></figure><p>Alternatively, you can provide a value to the 2 properties in the format <code class="language-text">span n</code> where <code class="language-text">n</code> is the number of rows the element should span.</p><p>So, instead of the previous properties used, you can use the following to make sure the red element spans 2 rows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.red</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span> <span class="token property">grid-row-start</span><span class="token punctuation">:</span> span 2<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will result in the same layout.</p><p>These properties are not only helpful for changing how many rows an element spans. They can also be used to completely control where each element is placed.</p><p>Let's say you want to place the blue column in the first row. You can apply the following styling to do that:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.blue</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span> <span class="token property">grid-row-start</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will result in the blue element being in the first row. However, as the placement of elements have changed the red element will be on the right.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.28.48-AM.png" class="kg-image" alt="CSS Grid Tutorial For Beginners" loading="lazy" width="2000" height="431" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-03-at-11.28.48-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-03-at-11.28.48-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-03-at-11.28.48-AM.png 1600w, https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.28.48-AM.png 2032w" sizes="(min-width: 720px) 720px"/></figure><p>To ensure that the blue item is on the right and the red element remains on the left, you can use the <code class="language-text">grid-column-start</code> property:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.blue</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span> <span class="token property">grid-row-start</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span> <span class="token property">grid-column-start</span><span class="token punctuation">:</span> 2<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will retain the original placement of the red element, but the blue item will be in the first column.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.30.38-AM.png" class="kg-image" alt="CSS Grid Tutorial For Beginners" loading="lazy" width="2000" height="429" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-03-at-11.30.38-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-03-at-11.30.38-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-03-at-11.30.38-AM.png 1600w, https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.30.38-AM.png 2032w" sizes="(min-width: 720px) 720px"/></figure><p>As you can see, you can use both properties for rows and columns to control many aspects of positioning and sizing of a grid.</p><h2 id="grid-areas">Grid Areas</h2><p>Instead of controlling a grid as columns and rows, you can control a grid as areas.</p><p>Let's say we want to implement a header, content, and sidebar layout. The green element will be the header, the red will be the content, and the blue will be the sidebar.</p><p>First, start by giving the different element area names using the <code class="language-text">grid-area</code> property:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.red</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span> <span class="token property">grid-area</span><span class="token punctuation">:</span> Content<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.green</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span> <span class="token property">grid-area</span><span class="token punctuation">:</span> Header<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.blue</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span> <span class="token property">grid-area</span><span class="token punctuation">:</span> Sidebar<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This gives the <code class="language-text">.red</code> element the grid-area name <code class="language-text">Content</code>, the <code class="language-text">.green</code> element the grid-area name <code class="language-text">Header</code>, and the <code class="language-text">.blue</code> element the grid-area <code class="language-text">Sidebar</code>.</p><p>Next, you use the <code class="language-text">grid-template-areas</code> property on the grid container element to determine how these different areas should be distributed. The <code class="language-text">grid-template-areas</code> takes as a value <code class="language-text">n</code> string values, where <code class="language-text">n</code> is the number of rows in the grid layout you're creating. The value will be the name of the areas separated by space. Each name specifies a column. So, if you want to have 2 columns in your grid and you want the <code class="language-text">Header</code> element to take 2 columns in a row, you can use the value <code class="language-text">"Header Header"</code> for the row.</p><p>In our example, we'll create 2 rows and 3 columns. The first row will just be the <code class="language-text">Header</code> which will span the 3 columns, and the second row will be the <code class="language-text">Content</code> which will span 2 columns and the <code class="language-text">Sidebar</code> which will be just one column:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.container</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span> <span class="token property">grid-template-areas</span><span class="token punctuation">:</span> <span class="token string">"Header Header Header"</span> <span class="token string">"Content Content Sidebar"</span><span class="token punctuation">;</span> <span class="token property">grid-row-gap</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span> <span class="token property">grid-column-gap</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span> <span class="token property">grid-auto-rows</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Since we want three columns in the grid, each string value in <code class="language-text">grid-template-areas</code> should have 3 area names. The first string value is for the first row in the grid. As we just want the <code class="language-text">Header</code> to occupy it the value will be the <code class="language-text">Header</code> repeated 3 times.</p><p>The second string value is for the second row. We want the <code class="language-text">Content</code> area to span 2 columns. So, in the string value we repeat the <code class="language-text">Content</code> area twice then the <code class="language-text">Sidebar</code>.</p><p>Notice that each string value is wrapped in <code class="language-text">"</code> and string values are separated by a space.</p><p>We also add a gap between rows and columns using <code class="language-text">grid-row-gap</code> and <code class="language-text">grid-column-gap</code>. We also set the default row height to <code class="language-text">100px</code> using <code class="language-text">grid-auto-rows</code>.</p><p>This will result in the following layout:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.50.08-AM.png" class="kg-image" alt="CSS Grid Tutorial For Beginners" loading="lazy" width="2000" height="438" srcset="https://backend.shahednasser.com/content/images/size/w600/2022/01/Screen-Shot-2022-01-03-at-11.50.08-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2022/01/Screen-Shot-2022-01-03-at-11.50.08-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2022/01/Screen-Shot-2022-01-03-at-11.50.08-AM.png 1600w, https://backend.shahednasser.com/content/images/2022/01/Screen-Shot-2022-01-03-at-11.50.08-AM.png 2038w" sizes="(min-width: 720px) 720px"/></figure><h2 id="fr-unit">fr Unit</h2><p>To ensure that columns or rows in a grid use the same height or width, you can use the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout#fixed_and_flexible_track_sizes">fr Unit</a>. For example, to create 3 columns each having the same width:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.container</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span> <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>3<span class="token punctuation">,</span> 1fr<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">grid-template-rows</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><h2 id="conclusion">Conclusion</h2><p>In this tutorial, you learned how CSS Grid Layout works in terms of rows, columns, and areas. Using a Grid Layout in CSS will help you control the size and placement of elements in your page or a container element.</p>]]></content:encoded></item><item><title><![CDATA[How To Make A Smartwatch App Successfully?]]></title><description><![CDATA[If you wish to know how to create an android wear app, follow the steps.]]></description><link>https://blog.shahednasser.com/how-to-make-a-smartwatch-app-successfully/</link><guid isPermaLink="false">Ghost__Post__61d43a3661dbd80628bf9c24</guid><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Kateryna Sukhotepla]]></dc:creator><pubDate>Tue, 04 Jan 2022 12:20:26 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/c2723e72e2e2588cb0cec0601fe6e424/simon-daoudi-2wFoa040m8g-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/c2723e72e2e2588cb0cec0601fe6e424/simon-daoudi-2wFoa040m8g-unsplash-2.jpg" alt="How To Make A Smartwatch App Successfully?"/><p>Devices are becoming more powerful and smaller, and they find their way in day-to-day objects. Considering the innovations in technologies, you can now carry personal computers in your pockets. Wearables come in different sizes, shapes, and sophistication. The smartwatches marketplace is also blooming, and more smartwatch app developers are being introduced. If you wish to know how to create an android wear app, follow the steps.</p><h2 id="being-efficient">Being Efficient</h2><p>When you create a wear OS app, ensure that it is <em>touch & glance </em>friendly. Users do not like to wear something where they have to struggle and deal with the application's functionality. Additionally, constant boot-ups can drain a person's patience. In an application, actionable notification is a suitable way to interact with users.</p><h2 id="being-reasonable-how-to-create-an-android-wear-app">Being Reasonable: How To Create An Android Wear App?</h2><p>These devices have direct access to sight and body parameters, opening a new horizon for creativity. But it is also not the best idea to overload the application. When you make an apple watch app, always check the model because the functionality varies with every set. One thing to remember is smartwatches are preferred for practicality.</p><h2 id="be-solicitous">Be Solicitous</h2><p>Balance is the key to a successful application, so you must keep this parameter in mind. Both too small or too large platforms will fail. The platform that sends updates to users now and then will annoy them. Because of that, they might mute the app as it irritates them. You should always try to be thoughtful before releasing an application to avoid that.</p><h2 id="designing-an-economic-app">Designing An Economic App</h2><p>While designing the application, the economic parameters should be kept into consideration. Take power processing and battery consumption into consideration. Never send too much data as a highly active screen can drain the battery. It will cause discomfort and distraction on a small screen.</p><p>So, did you ever want to own a smartwatch app? Have you been browsing for content that will provide in-depth information on the step-by-step procedure? At TopflightApps, we are aware of everything needed to create Wear OS or Watch OS application. Their blog section will provide details on <a href="https://topflightapps.com/ideas/how-to-develop-a-wearable-app-for-wear-os-and-watchos/">how to make a smartwatch app</a>. In this article, we include a shorter version to continue reading.</p><h2 id="be-compatible">Be Compatible</h2><p>Smartwatches are connected with smartphones to get content through a companion mobile application. In that way, it would be an excellent idea to explore the advantages of the functionalities of smartphones in the watch app. It is one step to consider when you build an apple watch app.</p><h2 id="understanding-the-differences">Understanding The Differences</h2><p>Preparing smartwatch applications seems to be different from normal applications. Even though you might find that both offer the same features and functions, things like hardware capacity, interface are different. Also, the design approach to follow on how to develop an android wear app is different. That's why you have to be a little careful when designing a smartwatch app.</p><h2 id="including-the-notification-bar">Including The Notification Bar</h2><p>Pay attention to the notification bar, and users might not find it difficult to access it. This button is a quick way of iterating and can appear in two forms; one is long-look, and another is short-look. Short-look offers a piece of brief information and eliminates vulnerable tests. The long-look offers minute details and can have up to four action buttons. The notification should be designed so that there are no complications.</p><h2 id="wrapping-up">Wrapping Up</h2><p>This is everything to know about how to create an android wear app. You can start looking for an efficient app designer and start the process. The experts will provide you with all the necessary details needed to have in an application.</p>]]></content:encoded></item><item><title><![CDATA[15 Free Programming Courses to Check Out in 2022]]></title><description><![CDATA[In this article, I'll share with you 15 programming courses that you can take to become a better programmer and learn new languages.]]></description><link>https://blog.shahednasser.com/15-free-programming-courses-to-check-out-in-2022/</link><guid isPermaLink="false">Ghost__Post__61d0ab0c61dbd80628bf9881</guid><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 03 Jan 2022 07:51:09 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/7ba78ca821fb59c20235977dcf45de59/bram-naus-n8Qb1ZAkK88-unsplash-3.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/7ba78ca821fb59c20235977dcf45de59/bram-naus-n8Qb1ZAkK88-unsplash-3.jpg" alt="15 Free Programming Courses to Check Out in 2022"/><p><em><a href="https://qvault.io/?via=shahed">Start learning online and land a job with the help of the community using Qvault.</a></em></p><p>With the start of a new year comes the urge to learn something new or expand on what you already know. As programmers, it's best to learn early on that you always need to learn and improve on your skills. </p><p>What's a better time to do that than with the beginning of a new year?</p><p>In this article, I'll share with you 15 programming courses that you can take to become a better programmer and learn new languages.</p><h2 id="git-github-crash-course-create-a-repository-from-scratch"><a href="https://www.udemy.com/course/git-and-github-crash-course-creating-a-repository-from-scratch/">Git & GitHub Crash Course: Create a Repository From Scratch!</a></h2><p>If you're a beginner to Git and GitHub, then this course is what you need. Learn how to create a repository, add files to it, compare between versions, and more. This 30-minute course will help you understand the basics of Git and get started with using it in your projects.</p><h2 id="web-design-for-web-developers-build-beautiful-websites"><a href="https://www.udemy.com/course/web-design-secrets/">Web Design for Web Developers: Build Beautiful Websites!</a></h2><p>I previously <a href="https://blog.shahednasser.com/web-design-tips-for-web-developers">wrote some tips</a> I learned from this course about web design. This course is resourceful for web developers that find it hard to grasp concepts related to web design. If you struggle to understand how you should layout your website or how to make it beautiful, then this quick and easy course is for you. This course is 1 hour long. </p><h2 id="cybersecurity-for-everyone"><a href="https://www.coursera.org/learn/cybersecurity-for-everyone">Cybersecurity for Everyone</a></h2><p>Whether you're a beginner or a seasoned developer, this course will help you understand Cybersecurity and manage its risks. This course lays the foundations of cybersecurity helping you understand its basics and how to apply its practices in your applications. This course is 22 hours long and you can earn a certificate after completing it.</p><h2 id="scripting-and-programming-foundations"><a href="https://www.edx.org/course/scripting-and-programming-foundations">Scripting and Programming Foundations</a></h2><p>This course is perfect for complete beginners in computer science as a whole. This course will help you understand programming theory and interpreting algorithms. It will also teach you about programming elements like variables, expressions, data types, and more. This course is 8 weeks long, estimated at 9-10 hours a week.</p><h2 id="computer-programming-for-everyone"><a href="https://www.futurelearn.com/courses/computer-programming-for-everyone">Computer Programming for Everyone</a></h2><p>This course is designed for beginner programmers, but also those who want to brush up on their knowledge and skills. In this course, you'll learn more about programming languages and algorithms in general. You'll also learn how algorithms can be applied in our daily lives. By the end of this course, you'll be able to create your first program. This course is estimated to be 2 weeks long, at 2 hours a week.</p><h2 id="programming-for-everybody-getting-started-with-python"><a href="https://www.edx.org/course/programming-for-everybody-getting-started-with-pyt">Programming for Everybody (Getting Started with Python)</a></h2><p>This is a course by the <a href="https://www.edx.org/school/michiganx">University of Michigan</a> and it will help you learn Python from scratch. You don't need any prerequisites to take this course. In this course, you'll learn about basics including variables and functions. The aim of this course is to prepare you for more advanced Python courses. The cool thing about this course is that all assignments and exercises can be done in the web browser directly. So, you can learn this course from your laptop or your phone on the move. This course is estimated to be 7 weeks long, at 2-4 hours a week.</p><h2 id="introduction-to-user-experience-design"><a href="https://www.coursera.org/learn/user-experience-design">Introduction to User Experience Design</a></h2><p>Being a programmer isn't just about learning how to code. There are a lot of concepts you should take the time to learn, and one of them is user experience (or UX). UX is important to ensure that when you create products or services, they are designed in a way that makes it easy for the user to use them. This course teaches you the basics of UX. It's 6 hours long and you will get a certificate at the end of it.</p><h2 id="linux-basics-the-command-line-interface"><a href="https://www.edx.org/course/linux-basics-the-command-line-interface">Linux Basics: The Command Line Interface</a></h2><p>Linux can be confusing for beginner programmers. However, once you understand how it works, you'll realize that it's the best OS option for programming. This course teaches you the basics of Linux and how you can utilize its commands to achieve the most out of it. You'll also learn by the end of this course how to create and execute a C program in Linux. This course is estimated to be 5 weeks long, at 3-5 hours per week.</p><h2 id="build-a-quiz-app-with-html-css-and-javascript"><a href="https://www.udemy.com/course/build-a-quiz-app-with-html-css-and-javascript/">Build a Quiz App with HTML, CSS, and JavaScript</a></h2><p>For beginner web developers who want to improve their skills, this course is for you. In this course, learn more about HTML, CSS, and JavaScript and how you can use them in practice while you create a quiz app. This course teaches you about different JavaScript concepts and APIs including Fetch. It also teaches you about different CSS concepts like Flexbox. This course is 2 hours long.</p><h2 id="introduction-to-programming-in-c"><a href="https://www.edx.org/course/introduction-to-programming-in-c">Introduction to Programming in C++</a></h2><p>C++ is <a href="https://pypl.github.io/PYPL.html">one of the top 5 popular languages</a> at the time of writing this. You can use C++ to create a variety of applications and games. This course will help you learn C++ from scratch. You'll learn about data types, iterations, and more. This course will lead you to create your first C++ application. After completing this course, you'll be able to take more advanced courses like <a href="https://www.edx.org/course/advanced-programming-in-c">Advanced Programming in C++</a>. This course is estimated to be 8 weeks long, at 6-8 hours per week.</p><h2 id="introduction-to-game-development-with-unity"><a href="https://www.udemy.com/course/introduction-to-game-development-with-unity/">Introduction to Game Development with Unity</a></h2><p>This course will teach you how to create a game using Unity. It will go through the steps starting from installing Unity, to fully creating the game and all the resources and elements that come into play when doing that. This course is good for those who want to start learning game development, as they can do it by practice. This course is almost 2 hours long. </p><h2 id="introduction-to-data-analytics-with-python"><a href="https://www.futurelearn.com/courses/introduction-to-data-analytics-with-python">Introduction to Data Analytics with Python</a></h2><p>This course is created by <a href="https://www.futurelearn.com">FutureLearn</a> in collaboration with <a href="https://www.tableau.com">Tableau</a>, a software that allows you to visualize and understand your data. This course will teach you how you can use python for data analytics. You'll learn advanced data operations and customizing visualizations using <a href="https://pandas.pydata.org">Pandas</a> and <a href="https://seaborn.pydata.org">Seaborn</a>. This course is estimated to be 4 weeks long, at 3 hours per week.</p><h2 id="learn-to-make-an-animated-image-gallery-using-html5"><a href="https://www.udemy.com/course/learn-to-make-an-animated-image-gallery-using-html5/">Learn to Make an Animated Image Gallery using HTML5</a></h2><p>For beginner web developers that are looking to expand their skills, this is another course they can take. In this course, you'll build an animated image gallery. Through this course, you'll learn more about HTML5 and JavaScript and how you can use them in your projects. This course is estimated to be an hour and 10 minutes long.</p><h2 id="introduction-to-augmented-reality-and-arcore"><a href="https://www.coursera.org/learn/ar">Introduction to Augmented Reality and ARCore</a></h2><p>This course for beginners will teach you about Augmented Reality (AR) and how you can build AR experiences using ARCore. This course talks about the basics of AR, allowing you to understand its basics, then shows you how you can build AR experiences using tools like Google Poly and Unity. This course is 11 hours long.</p><h2 id="selenium-basicsstep-by-step-for-beginners"><a href="https://www.udemy.com/course/selenium-basics-step-by-step-for-beginners/">Selenium Basics - Step by Step for Beginners</a></h2><p><a href="https://www.selenium.dev">Selenium</a> is an automation testing tool. This course will help you learn how to use Selenium from scratch. You'll learn about its different components, then you'll learn how to create a test automation script to test your website. This course is estimated to be 2 hours and a half long.</p><h2 id="conclusion">Conclusion</h2><p>In this article, I selected 15 courses that can you help you either improve on your skills or learn new ones. Use this article and the courses listed to start your year with new skills and spirit!</p>]]></content:encoded></item><item><title><![CDATA[Generate 10 QR Code Types with React]]></title><description><![CDATA[In this tutorial, you'll learn how to generate 10 different types of QR Codes in JavaScript, particularly React]]></description><link>https://blog.shahednasser.com/generate-10-qr-code-types-with-react/</link><guid isPermaLink="false">Ghost__Post__61c337f361dbd80628bf96b1</guid><category><![CDATA[React]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 27 Dec 2021 11:07:36 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/d92acf9981f2bc3be20eb786938ba4a7/proxyclick-visitor-management-system-EPeK7w5Eeic-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/d92acf9981f2bc3be20eb786938ba4a7/proxyclick-visitor-management-system-EPeK7w5Eeic-unsplash-2.jpg" alt="Generate 10 QR Code Types with React"/><p>QR Codes are square codes that people can scan to perform an action. That action can be just viewing some text, going to a URL, opening a location on a map, viewing a social media account, and more.</p><p>QR Codes are generally either used digitally on websites and apps to make it easier for users to perform something or used in printing when marketing your products or company. By printing your company URL's QR Code on your business card, you eliminate the need for people to type in the website to see it.</p><p>In this tutorial, you'll learn how to generate 10 different types of QR Codes in JavaScript, particularly React. You can see the full code on <a href="https://github.com/shahednasser/react-qr-tutorial">this GitHub repository</a>, and you can see it in live-action on <a href="https://shahednasser.github.io/react-qr-tutorial/">this website</a>.</p><h2 id="prerequisites">Prerequisites</h2><p>To follow along with this tutorial, you need to have both <a href="https://shahednasser.github.io/react-qr-tutorial/">Node.js</a> and NPM installed. NPM will be automatically installed when you install Node.js.</p><h2 id="setup-website">Setup Website</h2><p>To create a new React website, run the following command in your terminal:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-react-app react-qr-generator</code></pre></div><p>After this command is done, change to the newly created directory:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> react-qr-generator</code></pre></div><p>Then, install <a href="https://react-bootstrap.github.io">React Bootstrap</a> for easy styling:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> react-bootstrap bootstrap@5.1.3</code></pre></div><h3 id="install-qr-library">Install QR Library</h3><p>For this tutorial, you'll use the library <a href="https://www.npmjs.com/package/react-qr-code">react-qr-code</a>. This library provides a React component that, when you provide the text to be encoded into a QR Code, will display the QR Code for it.</p><p>To install the library run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> react-qr-code</code></pre></div><h3 id="home-page">Home Page</h3><p>Before you start creating all different types of QR Codes, you'll setup the main layout for the home page.</p><p>Change <code class="language-text">src/App.js</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> <span class="token string">'bootstrap/dist/css/bootstrap.min.css'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Container <span class="token keyword">from</span> <span class="token string">'react-bootstrap/Container'</span> <span class="token keyword">import</span> Tab <span class="token keyword">from</span> <span class="token string">'react-bootstrap/Tab'</span> <span class="token keyword">import</span> Row <span class="token keyword">from</span> <span class="token string">'react-bootstrap/Row'</span> <span class="token keyword">import</span> Col <span class="token keyword">from</span> <span class="token string">'react-bootstrap/Col'</span> <span class="token keyword">import</span> Nav <span class="token keyword">from</span> <span class="token string">'react-bootstrap/Nav'</span> <span class="token keyword">import</span> QRCode <span class="token keyword">from</span> <span class="token string">'react-qr-code'</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>qrText<span class="token punctuation">,</span> setQrText<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Container className<span class="token operator">=</span><span class="token string">'mx-auto'</span><span class="token operator">></span> <span class="token operator"><</span>h1 className<span class="token operator">=</span><span class="token string">'my-4'</span><span class="token operator">></span>Qr Generator<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token punctuation">{</span>qrText<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">&&</span> <span class="token operator"><</span>QRCode value<span class="token operator">=</span><span class="token punctuation">{</span>qrText<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator"><</span>h4 className<span class="token operator">=</span><span class="token string">'my-3'</span><span class="token operator">></span>Choose the type <span class="token keyword">of</span> QRCode format<span class="token operator"><</span><span class="token operator">/</span>h4<span class="token operator">></span> <span class="token operator"><</span>Tab<span class="token punctuation">.</span>Container defaultActiveKey<span class="token operator">=</span><span class="token string">"text"</span><span class="token operator">></span> <span class="token operator"><</span>Row<span class="token operator">></span> <span class="token operator"><</span>Col sm<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">3</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Nav variant<span class="token operator">=</span><span class="token string">"pills"</span> className<span class="token operator">=</span><span class="token string">"flex-column"</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Col<span class="token operator">></span> <span class="token operator"><</span>Col sm<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">9</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Tab<span class="token punctuation">.</span>Content<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Tab<span class="token punctuation">.</span>Content<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Col<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Row<span class="token operator">></span> <span class="token operator"><</span>Tab<span class="token punctuation">.</span>Container <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span></code></pre></div><p>Here, you create a <a href="https://react-bootstrap.github.io/components/tabs/#tabs-custom-layout">custom vertical tab layout</a> using React Bootstrap. This will allow you to show the different QR Code types on the left, and the content necessary for that type on the right.</p><p>You also create the state variable <code class="language-text">qrText</code> which will hold the text to generate a QR Code. When the <code class="language-text">qrText</code> is not empty, the <code class="language-text">QRCode</code> component from the library <code class="language-text">react-qr-code</code> will show the QR Code for that text.</p><p>In the next parts, you'll create components for 10 types of QR Codes. After creating each component, a tab will be added to it nested in <code class="language-text"><Nav></code>, and the component will be added as a tab-pane nested inside <code class="language-text"><Tab.Content></code>.</p><p>The components will be placed inside a new directory <code class="language-text">components</code> nested inside <code class="language-text">src</code>, so make sure to create that directory. </p><h2 id="plain-texturls-qr-codes">Plain Text/URLs QR Codes</h2><p>The most common QR Code type is a URL QR Code type. When a person scans the QR Code they'll be led to a webpage that this QR Code points to.</p><p>You can actually create a QR Code for any kind of text. It doesn't need to be a URL.</p><p>In this section, you'll create a component that takes text or URL and generate the QR Code for it.</p><p>Create the file <code class="language-text">src/components/Text.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button<span class="token punctuation">,</span> Form <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Text</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> setQrText <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>text<span class="token punctuation">,</span> setText<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setQrText</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Text or <span class="token constant">URL</span><span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"text"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>text<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setText</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Button variant<span class="token operator">=</span><span class="token string">"primary"</span> type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span> Generate <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Text</code></pre></div><p>The <code class="language-text">Text</code> component receives as a prop the function <code class="language-text">setQrText</code>, which will be used to set the text to be encoded as QR Code. Then, a form with one input "Text or URL" will be shown to the user.</p><p>Once the user enters the text or URL they want and clicks on the button "Generate", the text will be set with <code class="language-text">setQrText</code>. This will change the value of <code class="language-text">qrText</code> in the <code class="language-text">App</code> component, which will show a QR Code for that text.</p><p>Next, add the link for this new tab in <code class="language-text">src/App.js</code> nested in <code class="language-text"><Nav></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Nav<span class="token operator">></span> <span class="token operator"><</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span> <span class="token operator"><</span>Nav<span class="token punctuation">.</span>Link eventKey<span class="token operator">=</span><span class="token string">"text"</span><span class="token operator">></span>Text and URLs<span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token operator">></span></code></pre></div><p>And add the new Tab pane nested in <code class="language-text">Tab.Content</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Tab<span class="token punctuation">.</span>Content<span class="token operator">></span> <span class="token operator"><</span>Tab<span class="token punctuation">.</span>Pane eventKey<span class="token operator">=</span><span class="token string">"text"</span><span class="token operator">></span> <span class="token operator"><</span>Text setQrText<span class="token operator">=</span><span class="token punctuation">{</span>setQrText<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Tab<span class="token punctuation">.</span>Pane<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Tab<span class="token punctuation">.</span>Content<span class="token operator">></span></code></pre></div><p>Don't forget to import the new <code class="language-text">Text</code> component at the top of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Text <span class="token keyword">from</span> <span class="token string">'./components/Text'</span></code></pre></div><p>Let's test it out. Run the server with the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>This will run the server on <code class="language-text">localhost:3000</code> and the website will open in a browser. You should see one tab on the left and on the right a form that shows one text field with a button.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-21-at-7.13.31-PM.png" class="kg-image" alt="Generate 10 QR Code Types with React" loading="lazy" width="2000" height="344" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-21-at-7.13.31-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-21-at-7.13.31-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-21-at-7.13.31-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-21-at-7.13.31-PM.png 2034w" sizes="(min-width: 720px) 720px"/></figure><p>Try entering any text or URL. You should see a QR code generated at the top.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-5.41.49-PM.png" class="kg-image" alt="Generate 10 QR Code Types with React" loading="lazy" width="650" height="720" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-22-at-5.41.49-PM.png 600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-5.41.49-PM.png 650w"/></figure><p>If you try to scan the QR Code with your phone, you should either see the text you entered or see a URL to go to.</p><h2 id="geolocation-qr-codes">GeoLocation QR Codes</h2><p> QR Codes can be used to share a location with others. When the QR Code is scanned, the person will see the location on Google Maps.</p><p>The format of this QR Code's encoded value is as follows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">http://maps.google.com/maps?q={lat},{long}</code></pre></div><p>Where <code class="language-text">{lat}</code> is the latitude and <code class="language-text">{long}</code> is the longitude of the location.</p><p>In this section, you'll create a component that shows the user 2 fields Longitude and Latitude to allow them to generate a QR Code for that location. You'll also add the functionality to automatically add the latitude and longitude of their location.</p><p>Create <code class="language-text">src/components/Geolocation.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button<span class="token punctuation">,</span> Form<span class="token punctuation">,</span> Spinner <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Geolocation</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> setQrText <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>lat<span class="token punctuation">,</span> setLat<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>long<span class="token punctuation">,</span> setLong<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>locationLoading<span class="token punctuation">,</span> setLocationLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">getCurrentLocation</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setLocationLoading</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> navigator<span class="token punctuation">.</span>geolocation<span class="token punctuation">.</span><span class="token function">getCurrentPosition</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">pos</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setLat</span><span class="token punctuation">(</span>pos<span class="token punctuation">.</span>coords<span class="token punctuation">.</span>latitude<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setLong</span><span class="token punctuation">(</span>pos<span class="token punctuation">.</span>coords<span class="token punctuation">.</span>longitude<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setLocationLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span>err<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setLocationLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">enableHighAccuracy</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setQrText</span><span class="token punctuation">(</span><span class="token string">'http://maps.google.com/maps?q='</span> <span class="token operator">+</span> lat <span class="token operator">+</span> <span class="token string">','</span><span class="token operator">+</span> long<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Latitude<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"text"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>lat<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setLat</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Longitude<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"text"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>long<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setLong</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Button variant<span class="token operator">=</span><span class="token string">"secondary"</span> type<span class="token operator">=</span><span class="token string">"button"</span> className<span class="token operator">=</span><span class="token string">"me-2"</span> disabled<span class="token operator">=</span><span class="token punctuation">{</span>locationLoading<span class="token punctuation">}</span> onClick<span class="token operator">=</span><span class="token punctuation">{</span>getCurrentLocation<span class="token punctuation">}</span><span class="token operator">></span> <span class="token punctuation">{</span>locationLoading <span class="token operator">&&</span> <span class="token operator"><</span>Spinner animation<span class="token operator">=</span><span class="token string">"border"</span> className<span class="token operator">=</span><span class="token string">"me-2 align-middle"</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">}</span> Set Current Location <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span>Button variant<span class="token operator">=</span><span class="token string">"primary"</span> type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span> Generate <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Geolocation</code></pre></div><p>This component, similar to the previous one, receives the <code class="language-text">setQrText</code> function as a prop. 3 state variables are defined. <code class="language-text">lat</code> to hold the latitude value entered in the Latitude field, <code class="language-text">long</code> to hold the longitude value entered in the Longitude field, and <code class="language-text">locationLoading</code> to show a loading spinner when fetching the user's current location.</p><p>the <code class="language-text">getCurrentLocation</code> is executed when the user clicks on <code class="language-text">Set Current Location</code>. You first have to obtain the user's permission to get access to their location, then, when permitted, set the <code class="language-text">lat</code> and <code class="language-text">long</code> state variables based on the coordinates obtained.</p><p>Finally, when the form is submitted, the <code class="language-text">qrText</code> is set using <code class="language-text">setQrText</code> to the format shown before using <code class="language-text">lat</code> and <code class="language-text">lang</code>. </p><p>You just need to add the new tab in <code class="language-text">App.js</code> just like you did in the previous section under <code class="language-text"><Nav></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span> <span class="token operator"><</span>Nav<span class="token punctuation">.</span>Link eventKey<span class="token operator">=</span><span class="token string">"geo"</span><span class="token operator">></span>GeoLocation<span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span></code></pre></div><p>And add the new component as a tab-pane under <code class="language-text"><Tab.Content></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Tab<span class="token punctuation">.</span>Pane eventKey<span class="token operator">=</span><span class="token string">"geo"</span><span class="token operator">></span> <span class="token operator"><</span>Geolocation setQrText<span class="token operator">=</span><span class="token punctuation">{</span>setQrText<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Tab<span class="token punctuation">.</span>Pane<span class="token operator">></span></code></pre></div><p>And, of course, import the component at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Geolocation <span class="token keyword">from</span> <span class="token string">'./components/Geolocation'</span></code></pre></div><p>Let's test it out. Run the server if it isn't already running. You'll see a new tab "GeoLocation". When you click on the tab, you'll see 2 fields with 2 buttons.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-5.51.26-PM.png" class="kg-image" alt="Generate 10 QR Code Types with React" loading="lazy" width="2000" height="496" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-22-at-5.51.26-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-22-at-5.51.26-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-22-at-5.51.26-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-5.51.26-PM.png 2002w" sizes="(min-width: 720px) 720px"/></figure><p>Try entering a Latitude and Longitude, or set your current location with the "Set Current Location" button. When you click "Generate", a new QR Code will be generated.</p><p>If you try scanning the QR Code and if you have Google Maps installed, you'll see that you can open the QR Code directly in Google Maps and you'll see the location specified in the QR Code's value.</p><h2 id="calendar-qr-codes">Calendar QR Codes</h2><p>QR codes can be used to add events to a calendar. Using this QR Code, you can make it easier for your users or customers to remember events by easily scanning the QR Code and adding the event to their calendar.</p><p>The text format for a Calendar QR Code is as follows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">BEGIN:VCALENDAR\nBEGIN:VEVENT\nDTSTART:{start-date}\nDTEND:{end-date}\nSUMMARY:{title}\nEND:VEVENT\nEND:VCALENDAR</code></pre></div><p>This looks like a bunch of gibberish at first glance, but you can see that you're just specifying the start date, the end date, and the title of the event. Note that the start and end date are of the format <code class="language-text">YYYYMMDD</code> with no separation between any of them.</p><p>In this section, you'll create a component that shows the user 3 fields, one for the start date, one for the end date, and one for the title.</p><p>Create the file <code class="language-text">/src/components/Calendar.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button<span class="token punctuation">,</span> Form <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Calendar</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> setQrText <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>title<span class="token punctuation">,</span> setTitle<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>dateStart<span class="token punctuation">,</span> setDateStart<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>dateEnd<span class="token punctuation">,</span> setDateEnd<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> dateStartFormatted <span class="token operator">=</span> dateStart<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">-</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> dateEndFormatted <span class="token operator">=</span> dateEnd<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">-</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span> <span class="token function">setQrText</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">BEGIN:VCALENDAR\nBEGIN:VEVENT\nDTSTART:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>dateStartFormatted<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\nDTEND:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>dateEndFormatted<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\nSUMMARY:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>title<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\nEND:VEVENT\nEND:VCALENDAR</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Title<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"text"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>title<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setTitle</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Start Date<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"date"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>dateStart<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setDateStart</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>End Date<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"date"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>dateEnd<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setDateEnd</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Button variant<span class="token operator">=</span><span class="token string">"primary"</span> type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span> Generate <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Calendar</code></pre></div><p>This component defines 3 state variables: <code class="language-text">title</code>, <code class="language-text">dateStart</code>, and <code class="language-text">dateEnd</code>. When the user enters the values into the fields and clicks "Generate", <code class="language-text">qrText</code> will be set to the format stated above, with the values used in their specific places.</p><p>Just like you did in previous sections, go to <code class="language-text">src/App.js</code> and add a new tab under <code class="language-text"><Nav></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span> <span class="token operator"><</span>Nav<span class="token punctuation">.</span>Link eventKey<span class="token operator">=</span><span class="token string">"calendar"</span><span class="token operator">></span>Calendar<span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span></code></pre></div><p>Then, add the component as a tab-pane under <code class="language-text">Tab.Content</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Tab<span class="token punctuation">.</span>Pane eventKey<span class="token operator">=</span><span class="token string">"calendar"</span><span class="token operator">></span> <span class="token operator"><</span>Calendar setQrText<span class="token operator">=</span><span class="token punctuation">{</span>setQrText<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Tab<span class="token punctuation">.</span>Pane<span class="token operator">></span></code></pre></div><p>And import the <code class="language-text">Calendar</code> component at the top of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Calendar <span class="token keyword">from</span> <span class="token string">'./components/Calendar'</span></code></pre></div><p>Now, open the website. You should see a new tab "Calendar". Click on it and 3 fields will show up for the start date, end date, and title.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-7.04.20-PM.png" class="kg-image" alt="Generate 10 QR Code Types with React" loading="lazy" width="2000" height="686" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-22-at-7.04.20-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-22-at-7.04.20-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-22-at-7.04.20-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-7.04.20-PM.png 2018w" sizes="(min-width: 720px) 720px"/></figure><p>Try entering values for these fields then click "Generate". If you scan the QR Code generated you should be able to open your calendar and add an event with the title, start date, and end date you entered.</p><h2 id="mail-qr-codes">Mail QR Codes</h2><p>QR Codes can be used to allow your users or customers to easily email you. When they scan the QR Code, they can open a mail app with the to, subject, and message field already filled.</p><p>The format of a mail QR code is as follows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">MATMSG:TO:{to};SUB:{subject};BODY:{message};;</code></pre></div><p>Where <code class="language-text">{to}</code> is the email address this mail should be sent to, <code class="language-text">{subject}</code> is the subject of the email, and <code class="language-text">{message}</code> is the message to include in the body.</p><p>In this section, you'll create a Mail component with 3 fields: To, Subject and Message. You'll then generate the QR Code using the values of these fields.</p><p>Create <code class="language-text">src/components/Mail.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button<span class="token punctuation">,</span> Form <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Mail</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> setQrText <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>to<span class="token punctuation">,</span> setTo<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>subject<span class="token punctuation">,</span> setSubject<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>message<span class="token punctuation">,</span> setMessage<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setQrText</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">MATMSG:TO:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>to<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;SUB:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>subject<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;BODY:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>message<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>To Email<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"email"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>to<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setTo</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Subject<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"text"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>subject<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setSubject</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Message<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control <span class="token keyword">as</span><span class="token operator">=</span><span class="token string">"textarea"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>message<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setMessage</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Button variant<span class="token operator">=</span><span class="token string">"primary"</span> type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span> Generate <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Mail</code></pre></div><p>Similar to before, this creates 3 fields managed by 3 states, and when the "Generate" button is clicked the QR code will be generated using the format mentioned above.</p><p>Add the new tab in <code class="language-text">src/App.js</code> in <code class="language-text"><Nav></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span> <span class="token operator"><</span>Nav<span class="token punctuation">.</span>Link eventKey<span class="token operator">=</span><span class="token string">"mail"</span><span class="token operator">></span>Mail<span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span></code></pre></div><p>Then, add the tab-pane in <code class="language-text"><Tab.Control></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Tab<span class="token punctuation">.</span>Pane eventKey<span class="token operator">=</span><span class="token string">"mail"</span><span class="token operator">></span> <span class="token operator"><</span>Mail setQrText<span class="token operator">=</span><span class="token punctuation">{</span>setQrText<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Tab<span class="token punctuation">.</span>Pane<span class="token operator">></span></code></pre></div><p>Finally, import the <code class="language-text">Mail</code> component at the top of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Mail <span class="token keyword">from</span> <span class="token string">'./components/Mail'</span></code></pre></div><p>Open the website now and you should see a new Mail tab. Click on the tab and you'll see 3 fields with a button.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-21-at-7.48.46-PM.png" class="kg-image" alt="Generate 10 QR Code Types with React" loading="lazy" width="2000" height="775" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-21-at-7.48.46-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-21-at-7.48.46-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-21-at-7.48.46-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-21-at-7.48.46-PM.png 2028w" sizes="(min-width: 720px) 720px"/></figure><p>Enter values in these fields then click Generate. If you scan the QR code that is generated, you'll see that you can open a mail app and send an email with these fields prefilled.</p><h2 id="call-qr-code">Call QR Code</h2><p>QR Codes can be used to let your users or customers easily call you just by scanning the QR code.</p><p>The format for Call QR Code is as follows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">TEL:{phone_number}</code></pre></div><p>Where <code class="language-text">{phone_number}</code> is the phone number that the person will call when they scan the QR code.</p><p>In this section, you'll create a component that shows the user a field to enter their phone number, then generate the QR Code for it.</p><p>Create the file <code class="language-text">src/components/Call.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button<span class="token punctuation">,</span> Form <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Call</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> setQrText <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>phoneNumber<span class="token punctuation">,</span> setPhoneNumber<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setQrText</span><span class="token punctuation">(</span><span class="token string">"TEL:"</span> <span class="token operator">+</span> phoneNumber<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Phone Number<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"text"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>phoneNumber<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setPhoneNumber</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Button variant<span class="token operator">=</span><span class="token string">"primary"</span> type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span> Generate <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Call</code></pre></div><p>Similar to other components, this component has 1 state variable with a field to change its value. Then, on the form's submission, the text for the QR code is set to the format mentioned above.</p><p>Add in <code class="language-text">src/App.js</code> the tab for "Call":</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span> <span class="token operator"><</span>Nav<span class="token punctuation">.</span>Link eventKey<span class="token operator">=</span><span class="token string">"call"</span><span class="token operator">></span>Call<span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span></code></pre></div><p>And add a tab-pane for the <code class="language-text">Call</code> component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Tab<span class="token punctuation">.</span>Pane eventKey<span class="token operator">=</span><span class="token string">"call"</span><span class="token operator">></span> <span class="token operator"><</span>Call setQrText<span class="token operator">=</span><span class="token punctuation">{</span>setQrText<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Tab<span class="token punctuation">.</span>Pane<span class="token operator">></span></code></pre></div><p>Finally, import <code class="language-text">Call</code> at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Call <span class="token keyword">from</span> <span class="token string">'./components/Call'</span></code></pre></div><p>Open the website. You should see a new "Call" tab. If you click on it, you'll see one field for the phone number.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-7.17.16-PM.png" class="kg-image" alt="Generate 10 QR Code Types with React" loading="lazy" width="2000" height="340" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-22-at-7.17.16-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-22-at-7.17.16-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-22-at-7.17.16-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-7.17.16-PM.png 2000w" sizes="(min-width: 720px) 720px"/></figure><p>If you enter a phone number, click "Generate", then scan the QR Code, you'll be able to directly call the phone number.</p><h2 id="sms-qr-code">SMS QR Code </h2><p>QR Codes can be used to easily send SMS. You can show your users or customer a QR Code with your number and a prefilled message. When they scan it, they can directly open the messaging app and send a text message to the number with the message right away.</p><p>The format for SMS QR Codes is as follows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">smsto:{phoneNumber}:{message}</code></pre></div><p>Where <code class="language-text">{phoneNumber}</code> is the phone number to send the SMS to, and <code class="language-text">{message}</code> is the prefilled message. The <code class="language-text">{message}</code> is optional. So, you can just have the phone number and the user will be able to send you a message without prefilled content.</p><p>In this section, you'll create a component that shows the user 2 fields, one for phone number and one for the message content.</p><p>Create <code class="language-text">src/components/Sms.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button<span class="token punctuation">,</span> Form <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Sms</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> setQrText <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>phoneNumber<span class="token punctuation">,</span> setPhoneNumber<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>message<span class="token punctuation">,</span> setMessage<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setQrText</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">smsto:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>phoneNumber<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>message<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Phone Number<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"text"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>phoneNumber<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setPhoneNumber</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span><span class="token function">Message</span> <span class="token punctuation">(</span>Optional<span class="token punctuation">)</span><span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"text"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>message<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setMessage</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Button variant<span class="token operator">=</span><span class="token string">"primary"</span> type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span> Generate <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Sms</code></pre></div><p>Just like previous components, this component has 2 state variables for the phone number and message, then on form submission sets the text for the QR Code in the format mentioned above.</p><p>Add the tab in <code class="language-text">src/App.js</code> under <code class="language-text"><Nav></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span> <span class="token operator"><</span>Nav<span class="token punctuation">.</span>Link eventKey<span class="token operator">=</span><span class="token string">"sms"</span><span class="token operator">></span><span class="token constant">SMS</span><span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span></code></pre></div><p>And add the tab-pane for the <code class="language-text">Sms</code> component under <code class="language-text">Tab.Content</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Tab<span class="token punctuation">.</span>Pane eventKey<span class="token operator">=</span><span class="token string">"sms"</span><span class="token operator">></span> <span class="token operator"><</span>Sms setQrText<span class="token operator">=</span><span class="token punctuation">{</span>setQrText<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Tab<span class="token punctuation">.</span>Pane<span class="token operator">></span></code></pre></div><p>Finally, import the component at the top of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Sms <span class="token keyword">from</span> <span class="token string">'./components/Sms'</span></code></pre></div><p>Open the website now and click on the new "SMS" tab. You'll see 2 fields for phone number and message.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-21-at-7.52.45-PM.png" class="kg-image" alt="Generate 10 QR Code Types with React" loading="lazy" width="2000" height="497" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-21-at-7.52.45-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-21-at-7.52.45-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-21-at-7.52.45-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-21-at-7.52.45-PM.png 2046w" sizes="(min-width: 720px) 720px"/></figure><p>Enter the phone number and optionally the message, click Generate, then scan the QR code. You'll be able to open the messaging app with the number and the message (if you entered one) filled in.</p><h2 id="wifi-qr-codes">Wifi QR Codes</h2><p>QR Codes can be used to easily connect to a Wifi network. When a person scans the QR code, they can join the network.</p><p>The Wifi QR code has the following format:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">WIFI:T:{authentication};S:{name};P:{password};H:{hidden};</code></pre></div><p><code class="language-text">{authentication}</code> can either be <code class="language-text">nopass</code>, <code class="language-text">WPA</code> or <code class="language-text">WEP</code>. <code class="language-text">{name}</code> is the name or SSID of the network. <code class="language-text">{password}</code> is the password of the network and optional. <code class="language-text">{hidden}</code> is a boolean value (true or false) that indicates whether this network is hidden or not.</p><p>In this section, you'll create a component that shows the user 4 components for the 4 fields mentioned above, then generates the QR code for it.</p><p>Create <code class="language-text">src/components/Wifi.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button<span class="token punctuation">,</span> Form <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Wifi</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> setQrText <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>authentication<span class="token punctuation">,</span> setAuthentication<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">'nopass'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>name<span class="token punctuation">,</span> setName<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>password<span class="token punctuation">,</span> setPassword<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>hidden<span class="token punctuation">,</span> setHidden<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setQrText</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">WIFI:T:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>authentication<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;S:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>authentication <span class="token operator">!==</span> <span class="token string">'nopass'</span> <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">P:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>password<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">H:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>hidden<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Authentication type<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Select value<span class="token operator">=</span><span class="token punctuation">{</span>authentication<span class="token punctuation">}</span> aria<span class="token operator">-</span>label<span class="token operator">=</span><span class="token string">"Authentication"</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setAuthentication</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"nopass"</span><span class="token operator">></span>No Password<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"WEP"</span><span class="token operator">></span><span class="token constant">WEP</span><span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"WPA"</span><span class="token operator">></span><span class="token constant">WPA</span><span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Select<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Network <span class="token function">Name</span> <span class="token punctuation">(</span><span class="token constant">SSID</span><span class="token punctuation">)</span><span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"text"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>name<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setName</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span><span class="token function">Password</span> <span class="token punctuation">(</span>Optional<span class="token punctuation">)</span><span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"password"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>password<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setPassword</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Hidden<span class="token operator">?</span><span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Check type<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">'checkbox'</span><span class="token punctuation">}</span> checked<span class="token operator">=</span><span class="token punctuation">{</span>hidden<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setHidden</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>checked<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Button variant<span class="token operator">=</span><span class="token string">"primary"</span> type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span> Generate <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Wifi</code></pre></div><p>Add in <code class="language-text">src/App.js</code> the tab in <code class="language-text"><Nav></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span> <span class="token operator"><</span>Nav<span class="token punctuation">.</span>Link eventKey<span class="token operator">=</span><span class="token string">"wifi"</span><span class="token operator">></span>Wifi<span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span></code></pre></div><p>And add <code class="language-text">Wifi</code> as a tab-pane in <code class="language-text"><Tab.Content></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Tab<span class="token punctuation">.</span>Pane eventKey<span class="token operator">=</span><span class="token string">"wifi"</span><span class="token operator">></span> <span class="token operator"><</span>Wifi setQrText<span class="token operator">=</span><span class="token punctuation">{</span>setQrText<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Tab<span class="token punctuation">.</span>Pane<span class="token operator">></span></code></pre></div><p>Finally, import <code class="language-text">Wifi</code> at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Wifi <span class="token keyword">from</span> <span class="token string">'./components/Wifi'</span></code></pre></div><p>If you open the website and click on the Wifi tab, you should see 4 fields.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-7.32.19-PM.png" class="kg-image" alt="Generate 10 QR Code Types with React" loading="lazy" width="2000" height="770" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-22-at-7.32.19-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-22-at-7.32.19-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-22-at-7.32.19-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-7.32.19-PM.png 2010w" sizes="(min-width: 720px) 720px"/></figure><p>Enter values for the fields then click Generate. If you scan the generated QR Code, you'll be able to automatically connect to the Wifi network.</p><h2 id="youtube-qr-codes">YouTube QR Codes</h2><p>QR Codes can be used to easily open a YouTube video. They have the following format:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">youtube://{videoId}</code></pre></div><p>Where <code class="language-text">{videoId}</code> is the ID of a video. You can obtain the ID of a video from the <code class="language-text">v</code> parameter in the URL of the video:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">https://www.youtube.com/watch?v={videoId}</code></pre></div><p>You'll create in this section a component that shows a field for the video's ID then generate the QR code for it.</p><p>Create <code class="language-text">js/components/Youtube.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button<span class="token punctuation">,</span> Form <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Youtube</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> setQrText <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>videoId<span class="token punctuation">,</span> setVideoId<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setQrText</span><span class="token punctuation">(</span><span class="token string">'youtube://'</span> <span class="token operator">+</span> videoId<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Video <span class="token constant">ID</span><span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"text"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>videoId<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setVideoId</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Button variant<span class="token operator">=</span><span class="token string">"primary"</span> type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span> Generate <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Youtube</code></pre></div><p>Add the new tab in <code class="language-text">src/App.js</code> inside <code class="language-text"><Nav></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span> <span class="token operator"><</span>Nav<span class="token punctuation">.</span>Link eventKey<span class="token operator">=</span><span class="token string">"youtube"</span><span class="token operator">></span>Youtube<span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span></code></pre></div><p>And add the tab-pane for YouTube:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Tab<span class="token punctuation">.</span>Pane eventKey<span class="token operator">=</span><span class="token string">"youtube"</span><span class="token operator">></span> <span class="token operator"><</span>Youtube setQrText<span class="token operator">=</span><span class="token punctuation">{</span>setQrText<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Tab<span class="token punctuation">.</span>Pane<span class="token operator">></span></code></pre></div><p>Finally, import the <code class="language-text">Youtube</code> component at the top of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Youtube <span class="token keyword">from</span> <span class="token string">'./components/Youtube'</span></code></pre></div><p>Open the website and click on the Youtube tab. You'll see one field to enter the video ID.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-7.36.53-PM.png" class="kg-image" alt="Generate 10 QR Code Types with React" loading="lazy" width="2000" height="306" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-22-at-7.36.53-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-22-at-7.36.53-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-22-at-7.36.53-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-7.36.53-PM.png 2010w" sizes="(min-width: 720px) 720px"/></figure><p>Enter a video's ID then click Generate. If you scan the QR code, you can open the video in the YouTube app right away.</p><h2 id="instagram-qr-codes">Instagram QR Codes</h2><p>QR Codes can be used to lead people to your Instagram account. The format is just like a URL to your profile:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">https://instagram.com/{username}</code></pre></div><p>Where <code class="language-text">{username}</code> is the username of the profile to open in the Instagram app.</p><p>Create <code class="language-text">src/components/Instagram.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button<span class="token punctuation">,</span> Form <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Instagram</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> setQrText <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>username<span class="token punctuation">,</span> setUsername<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setQrText</span><span class="token punctuation">(</span><span class="token string">'https://instagram.com/'</span> <span class="token operator">+</span> username<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Username<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"text"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>username<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setUsername</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Button variant<span class="token operator">=</span><span class="token string">"primary"</span> type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span> Generate <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Instagram</code></pre></div><p>In <code class="language-text">src/App.js</code> add the new tab under <code class="language-text"><Nav></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span> <span class="token operator"><</span>Nav<span class="token punctuation">.</span>Link eventKey<span class="token operator">=</span><span class="token string">"instagram"</span><span class="token operator">></span>Instagram<span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span></code></pre></div><p>And add the new tab-pane for <code class="language-text">Instagram</code> under <code class="language-text"><Tab.Content></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Tab<span class="token punctuation">.</span>Pane eventKey<span class="token operator">=</span><span class="token string">"instagram"</span><span class="token operator">></span> <span class="token operator"><</span>Instagram setQrText<span class="token operator">=</span><span class="token punctuation">{</span>setQrText<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Tab<span class="token punctuation">.</span>Pane<span class="token operator">></span></code></pre></div><p>Finally, import <code class="language-text">Instagram</code> at the top of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Instagram <span class="token keyword">from</span> <span class="token string">'./components/Instagram'</span></code></pre></div><p>Open the website and click on the Instagram tab. You'll see a field to enter your username.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-7.40.28-PM.png" class="kg-image" alt="Generate 10 QR Code Types with React" loading="lazy" width="2000" height="391" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-22-at-7.40.28-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-22-at-7.40.28-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-22-at-7.40.28-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-7.40.28-PM.png 2038w" sizes="(min-width: 720px) 720px"/></figure><p>Enter a username and click on Generate. If you scan the generated QR code, you can open the username's profile right away in the Instagram app.</p><h2 id="twitter-qr-codes">Twitter QR Codes</h2><p>QR Codes can be used to lead people to your Twitter profile or to Tweet something. </p><p>The format to lead to a Twitter profile is as follows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">https://twitter.com/{username}</code></pre></div><p>This is similar to Instagram. When the QR Code for this text is scanned, the profile for <code class="language-text">{username}</code> will be opened in the Twitter app.</p><p>The format to allow people to Tweet something with prefilled content is as follows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">https://twitter.com/intent/tweet?text={content}</code></pre></div><p>Where <code class="language-text">{content}</code> is the content of the tweet.</p><p>In this section, you'll create a component with 2 fields, one to determine the type of Twitter QR Code, and one for the content of the text.</p><p>Create <code class="language-text">src/components/Twitter.js</code> with the following text:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button<span class="token punctuation">,</span> Form <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Twitter</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> setQrText <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>type<span class="token punctuation">,</span> setType<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">'profile'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>text<span class="token punctuation">,</span> setText<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setQrText</span><span class="token punctuation">(</span><span class="token string">'https://twitter.com/'</span> <span class="token operator">+</span> <span class="token punctuation">(</span>type <span class="token operator">===</span> <span class="token string">'profile'</span> <span class="token operator">?</span> text <span class="token operator">:</span> <span class="token string">'intent/tweet?text='</span> <span class="token operator">+</span> text<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Type<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Select value<span class="token operator">=</span><span class="token punctuation">{</span>type<span class="token punctuation">}</span> aria<span class="token operator">-</span>label<span class="token operator">=</span><span class="token string">"Type"</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setType</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"profile"</span><span class="token operator">></span>Profile<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"tweet"</span><span class="token operator">></span>Tweet<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Select<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Username or Tweet Text<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"text"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>text<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setText</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Button variant<span class="token operator">=</span><span class="token string">"primary"</span> type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span> Generate <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Twitter</code></pre></div><p>In <code class="language-text">src/App.js</code> add the new tab in <code class="language-text"><Nav></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span> <span class="token operator"><</span>Nav<span class="token punctuation">.</span>Link eventKey<span class="token operator">=</span><span class="token string">"twitter"</span><span class="token operator">></span>Twitter<span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Item<span class="token operator">></span></code></pre></div><p>And add the <code class="language-text">Twitter</code> component in <code class="language-text"><Tab.Content></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Tab<span class="token punctuation">.</span>Pane eventKey<span class="token operator">=</span><span class="token string">"twitter"</span><span class="token operator">></span> <span class="token operator"><</span>Twitter setQrText<span class="token operator">=</span><span class="token punctuation">{</span>setQrText<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Tab<span class="token punctuation">.</span>Pane<span class="token operator">></span></code></pre></div><p>Finally, import the <code class="language-text">Twitter</code> component at the top of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Twitter <span class="token keyword">from</span> <span class="token string">'./components/Twitter'</span></code></pre></div><p>Open the website now and click on the Twitter tab. You'll see 2 fields.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-7.45.48-PM.png" class="kg-image" alt="Generate 10 QR Code Types with React" loading="lazy" width="2000" height="487" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-22-at-7.45.48-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-22-at-7.45.48-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-22-at-7.45.48-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-22-at-7.45.48-PM.png 2004w" sizes="(min-width: 720px) 720px"/></figure><p>Choose one of the types and enter the text based on what you chose, then click Generate. If you scan the QR code, based on the type you chose you'll either be led to the user's profile or to tweet something with the text you entered prefilled.</p><h2 id="conclusion">Conclusion</h2><p>QR Codes simplify doing certain actions and allow people to easily interact with your websites, products, or services. These 10 QR code types are just some of the actions you can let users perform, and you can easily generate QR codes in JavaScript, specifically React, using the react-qr-code library.</p>]]></content:encoded></item><item><title><![CDATA[What is Mathematical Induction]]></title><description><![CDATA[Mathematical induction is one of the most important proof techniques in math.]]></description><link>https://blog.shahednasser.com/what-is-mathematical-induction/</link><guid isPermaLink="false">Ghost__Post__61cb166d61dbd80628bf9865</guid><category><![CDATA[Mathematics]]></category><dc:creator><![CDATA[Mohammad Nasser]]></dc:creator><pubDate>Sun, 26 Dec 2021 13:54:00 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/830dbdca6e3bb3b7fdfb0886d8781c84/tom-wilson-Em2hPK55o8g-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/830dbdca6e3bb3b7fdfb0886d8781c84/tom-wilson-Em2hPK55o8g-unsplash-2.jpg" alt="What is Mathematical Induction"/><p>Mathematical induction is one of the most important proof techniques in math.<br>This technique is like a chain of objects in the picture attached.</br></p><p>Actually, we use this technique in order to prove that a statement p(n) is true for any natural number n.</p><p>This technique is divided into two parts:</p><p>First part, we have to show that p(0) is true, that is the statement is true for n=0 (actually not especially for n=0, but for the lower bound of n that is mentioned in the theorem).</p><p>In the second part, we assume that p(n) is true and then we prove that p(n+1) is also true.</p><p>From these two steps, we can easily see that p(0) is true, which implies that p(1) is true, which yields also that p(2) is true, and so on we get p(n) is true for any natural number n.</p><p>This way of thinking is actually brilliant, and it is one of the issues that mix logic with math.</p>]]></content:encoded></item><item><title><![CDATA[Get started with Medusa Part 3: Exploring our Admin Dashboard]]></title><description><![CDATA[In this section, you’ll learn more about the admin dashboard and how to customize it.]]></description><link>https://dev.to/medusajs/get-started-with-medusa-part-3-exploring-our-admin-dashboard-1nkn</link><guid isPermaLink="false">Ghost__Post__61c1aa5561dbd80628bf9687</guid><category><![CDATA[Reviews]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[eCommerce]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 21 Dec 2021 10:28:37 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/11f44065fa9e249852d5cb0e3fcbcab5/Frame-44.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/11f44065fa9e249852d5cb0e3fcbcab5/Frame-44.jpg" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard"/><p>In the <a href="https://blog.shahednasser.com/get-started-with-medusa-part-2-make-the-server-your-own/">previous parts of the series</a>, I went over how to set up <a href="https://www.medusajs.com/">Medus</a><a href="https://www.medusajs.com/">a</a>, the project as a whole and how it compares against e-commerce platforms like Shopify. I also went over how to add new API endpoints, services, and subscribers. I added a new endpoint to retrieve the top products, a service to set and get a product’s number of sales, and a subscriber that, when an order is placed, increments a product’s number of sales.</p><p>In this section, you’ll learn more about the admin dashboard. You’ll see the main features of it and how they set Medusa apart from other e-commerce platforms. Then, as a continuation to what I added to the backend in the previous part, you’ll learn how to customize the admin platform by adding a page to view the top selling products.</p><p>The code for this tutorial can be found on <a href="https://github.com/shahednasser/medusa-admin-tutorial">this GitHub repository</a>. You can also use <a href="https://github.com/shahednasser/medusa-store-tutorial">this GitHub repository</a> for the changes I made last time to Medusa’s backend. At last, should you have any questions in regard to the setup, then feel free to catch the Medusa team directly on their <a href="https://discord.gg/F87eGuwkTp">Discord</a>.</p><h2 id="dashboard-key-features">Dashboard Key Features</h2><h3 id="settings">Settings</h3><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8RM3Xjki--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6m1ad7v2ncowxpwxquwe.png" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy"/></figure><p>Medusa provides an easy-to-use interface to manage the core settings and enable you to set up unique configurations across stores in different regions. Using the admin dashboard, you can manage simple settings like the website’s name, and more essential settings like currencies or shipping methods.</p><p>In the admin dashboard, you can add as many regions as you want to your store. Adding a region means you can specify for one or more countries a set of rules including tax rules, currency, payment methods, and more.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F4f4dmI_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4toob3ruw262tzmvnsj4.png" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy"/></figure><p>This allows you to customize each regional experience by providing local currency, payment, and shipping options in line with the customer needs and regulations of the paritcular region. This helps you cater your e-commerce platform to more users around the world, and provide optimized local solutions they are used to working with.</p><p>Medusa also comes with multi-currency support, and you can add all currencies to your store directly from the dashboard. You can specify the default currency and choose which other currencies that can be used in your store.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c54LKZ_X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/096ojez8ljrdygit9yfy.png" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy"/></figure><p>Adding to the customization possibilities, Medusa enables you to set specific prices for each product per currency. This allows you to manage and format the price yourself and you avoid many of the notriously bad looking price roudings that normally accumulates with non-customized pricing (e.g. a product costing $17.89 instead of just $18)</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2S7Famwa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ti1es2vmrhxihygftv31.png" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy"/></figure><p>The regional adaptiability of Medusa was built-in because many of the existing solutions (e.g. Shopify, WooCommerce, etc.) lacked regional flexibility. To solve multi-currency problems or to integrate with local payment/shipping providers the solution for other platforms have often been to create seperate stores. This eventually leads to a setup where you have a new store for each market which is a real hurdle to maintain. Instead, Medusa ensures you can customize setting and collect orders across countries in one backend without the need to manage multiple stores at once.</p><h3 id="order-management">Order Management</h3><p>From the admin dashboard, you can view all orders and manage them efficiently. You can easily view the information of each order and the customer that placed the order, but you can also do much more than that.</p><p>On an order’s page, you can view all details necessary related to the customer and shipping and payment methods. You can also see a timeline that demonstrates clearly the stages this order went through until fulfillment for customer service purposes.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dfe1l_a3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5veoxiyptsy9i3bxp5ks.png" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy"/></figure><p>Something you’ll notice as a constant throughout the main dashboard is that you can access any entity’s raw data right from the dashboard. The raw data is the information about that entity in JSON format, just how you’d receive it from the backend using the APIs. For developers, this is a time-saving features as you don’t have to send out requests to the server whenever you need to debug or check something. You can just view it on the dashboard. This applies to orders, products, and other entities as well.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yy_a3q2D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lo00kkl1ug3u11b1naag.png" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy"/></figure><p>In addition, you can fulfill an order, which means shipping it out to the customer, using the shipping methods you add to your store. You can also mark items shipped or cancel shipping items for easily maneuvering as a customer service professional.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ui3-Lpqs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xd0j3yq97b50yhhq1e3t.png" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy"/></figure><p>Another feature that Medusa provides for order management is the ability to create draft orders directly from the admin. A lot of businesses take orders from different channels, not just on the website. If a business takes an order over the phone, for example, it becomes a hassle to manage orders separately from the website’s orders.</p><p>On the admin dashboard, you can create a draft order that helps solve such use cases. When you create an order, you can search from the products already existing on the platform and add them to the order. Alternatively, you can add a custom item that doesn’t necessarily exist on the platform. This is very useful if you sell different products or services on different channels.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Lho1_aki--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpg79o2yp6mo1t85qrkc.png" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy"/></figure><p>You can also either select an existing customer for the order or create a new one.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Qbum_fJ_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7l05qm476ufh0hh0ebt.png" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy"/></figure><p>You can choose a shipping method and even set a custom price for it. This feature is pretty detailed and makes managing orders, regardless of their origin, very simple.<br>**</br></p><h3 id="exchanges-swaps-and-claim-handling">Exchanges, Swaps, and Claim Handling</h3><p><a href="https://www.invespcro.com/blog/ecommerce-product-return-rate-statistics/">30% of e-commerce orders are returned</a>. The customer might not like the product. The size didn’t fit them or they picked a wrong size. In worse cases, there could be a defect in the product.</p><p>Although this is something essential to handle, most e-commerce platforms don’t support the handling of these cases natively and you would need to purchase external plugins or modules to add such features.</p><p>Medusa provides support of these features out of the box. In the admin panel, you can issue a return request for any item in an order. You can specify the shipping method to use, and the refund amount, if any.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--djq7L7u1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xse7jdtyq1bu4x6zderd.png" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy"/></figure><p>In addition, you can issue a swap request. You can swap an item for another with details regarding the shipping method to use and the difference in the amount after the swap.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oVM0Uh4d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yp4rwhsst34kgg2zl9lc.png" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy"/></figure><p>You can also create a claim to handle different cases or log reasons of why an item should be returned or replaced. This option offers more details when handling certain cases of malfunctioned items, wrong items delivered, and more.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rOXsDPHZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ohtl4962wlgwr57qbre9.png" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy"/></figure><p>And the best part about all of this is that these features are automated. For the customer, they can always file a return request. They will then receive and email with the next steps they need to take to return the order. This leads to better user experience, and as research suggest, 92% of customers end up placing orders in the future if <a href="https://www.invespcro.com/blog/ecommerce-product-return-rate-statistics/">the order return experience was easy and simple</a>.</p><p>The automation of these features also affect the accounting side of things. Any refunded amounts or additional amounts added due to a refund or swap is all logged in the system and automatically cleared on the acoounting side so that you do not need to manually adjust for differences between swaps or return orders.</p><h2 id="other-features">Other Features</h2><p>In addition to some of these key features, Medusa offers the basic features you expect from every e-commerce platform.</p><h3 id="product-management">Product Management</h3><p>On the admin dashboard, you can manage your products including variants, stock and inventory, and more.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pXHfy3MW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gsu0m9cpy8pa37v4x616.png" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy"/></figure><h3 id="customer-management">Customer Management</h3><p>You can likewise manage your customers from the admin dashboard. You can see their order details, shipping address, and more.</p><h3 id="discount-management">Discount Management</h3><p>The admin dashboard also lets you add and manage discounts with many options. These options include number of usages, type of discount (free shipping or fixed amount), how to apply the discount, and more.</p><h3 id="gift-cards">Gift Cards</h3><p>Another cool feature that the admin dashboard has is managing gift cards. As opposed to other platforms like Magento that only offer Gift Cards for their <a href="https://docs.magento.com/user-guide/catalog/product-gift-card-create.html">paid commerce version</a>, Medusa lets you add gift cards and manage details like image, values, description, and more.</p><h3 id="easily-add-integrations">Easily Add Integrations</h3><p>The coolest part about Medusa is that you can integrate popular or custom services easily into the admin dashboard. You can integrate the admin dashboard with CMS tools like <a href="https://docs.medusajs.com/how-to/making-your-store-more-powerful-with-contentful">Contentful</a> or <a href="https://strapi.io/">Strapi</a> to add more CMS related fields and features.</p><p>You can also add integrations that help you manage your platform’s marketing and analytics. You can integrate email services like <a href="https://sendgrid.com/">Sendgrid</a> or <a href="https://mailchimp.com/">Mailchimp</a>.</p><p>Of course, you can add your own custom integrations as well based on your use case. For example, you can add integrations for payment or shipment methods that are specific to your local customers.</p><h2 id="round-up">Round Up</h2><p>Comparing Medusa to many of the existing proprietary platforms on the market, it is clear that much of the standard ecommerce functionalities are built-in to Medus. In additon, there has been a focus on adding additional value in areas that were not well covered such as regional extendibility, exchange/return handling etc.</p><p>In addition, due to its open source nature you can customize the admin dashboard as it fits your needs. From the look and feel to the functionalities it provides. You can change up the admin panel to make it your own.</p><h2 id="customize-the-admin-dashboard">Customize the Admin Dashboard</h2><p>A unique attribute for an open-source project like Medusa which really do not set any boundaries to the types of customization you want to make on the backend. In this section, you will learn how to customize the Admin dashboard to add your own features. As a continuation to the previous part, you will add a page to view the top selling products on the admin dashboard.</p><p><strong>Add Admin Endpoint</strong><br>In the last tutorial, you added an endpoint on the backend to get the top selling endpoints. This time, you’ll add the same endpoint for the admin side to access.</br></p><p>To make sure the admin panel is able to access the endpoint, you need to add some configurations related to cross-origin resource sharing (or CORS).</p><p>In the backend in the file <code class="language-text">src/api/index.js</code> add the following imports at the top of the file:<br/></p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"> <span class="token keyword">import</span> bodyParser <span class="token keyword">from</span> <span class="token string">"body-parser"</span> <span class="token keyword">import</span> cors <span class="token keyword">from</span> <span class="token string">"cors"</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> projectConfig <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"../../medusa-config"</span> </code></pre></div><p>Then, below the endpoint added in the previous tutorial, add the following:<br/></p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"> <span class="token keyword">const</span> corsOptions <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">origin</span><span class="token operator">:</span> projectConfig<span class="token punctuation">.</span> admin_cors<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">credentials</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> router<span class="token punctuation">.</span><span class="token function">options</span><span class="token punctuation">(</span><span class="token string">'/admin/top-products'</span><span class="token punctuation">,</span> <span class="token function">cors</span><span class="token punctuation">(</span>corsOptions<span class="token punctuation">)</span><span class="token punctuation">)</span> router<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"/admin/top-products"</span><span class="token punctuation">,</span> <span class="token function">cors</span><span class="token punctuation">(</span>corsOptions<span class="token punctuation">)</span><span class="token punctuation">,</span> bodyParser<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> topProductsService <span class="token operator">=</span> req<span class="token punctuation">.</span>scope<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">"topProductsService"</span><span class="token punctuation">)</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">products</span><span class="token operator">:</span> <span class="token keyword">await</span> topProductsService<span class="token punctuation">.</span><span class="token function">getTopProducts</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> </code></pre></div><p>This will make use of the <a href="https://expressjs.com/en/resources/middleware/cors.html">cors</a> middleware, passing it the admin CORS configuration from <code class="language-text">medusa-config.js</code> in the root of the backend. Then, you add an <code class="language-text">OPTIONS</code> and <code class="language-text">GET</code> endpoints. In the <code class="language-text">GET</code> endpoint, you retrieve the top products just like you did last time.</p><p><strong>Add New Admin Page</strong><br>Next, you’ll add the new admin page to show the top products. You’ll add the page as a sub-page of the <em>Products</em> section of the admin panel. So, you need to add the page and add it in the sidebar under <em>Products</em>.</br></p><p>Pages in the admin dashboard are added under the directory <code class="language-text">src/domain</code>. In that directory, top pages in the admin dashboard are the main directories, then, inside each of those directories you’ll find JavaScript files for each page.</p><p>Let’s take a look at the <code class="language-text">products</code> directory, for instance. You’ll find inside it an <code class="language-text">index.js</code> file, which includes the page that you first see when you click on <em>Products</em> in the sidebar. You’ll also find a router inside the file like the following:<br/></p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"> <span class="token keyword">const</span> <span class="token function-variable function">Products</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Router<span class="token operator">></span> <span class="token operator"><</span>ProductIndex path<span class="token operator">=</span><span class="token string">"/"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Details path<span class="token operator">=</span><span class="token string">":id"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>New path<span class="token operator">=</span><span class="token string">"new"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Router<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre></div><p>This adds nested routes under the <code class="language-text">/products</code> route.</p><p>You’ll find under the <code class="language-text">products</code> directory other directories with nested files for each page.</p><p>So, to add a new page you need to create the file <code class="language-text">top-selling.js</code> under the <code class="language-text">products</code> directory, then add it as a nested route in <code class="language-text">index.js</code>.</p><p>Create the file <code class="language-text">src/domain/products/top-selling.js</code> with the following content:<br/></p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"> <span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Link <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"gatsby"</span> <span class="token keyword">import</span> _ <span class="token keyword">from</span> <span class="token string">"lodash"</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Flex<span class="token punctuation">,</span> Text<span class="token punctuation">,</span> Box<span class="token punctuation">,</span> Image <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"rebass"</span> <span class="token keyword">import</span> ImagePlaceholder <span class="token keyword">from</span> <span class="token string">"../../assets/svg/image-placeholder.svg"</span> <span class="token keyword">import</span> Spinner <span class="token keyword">from</span> <span class="token string">"../../components/spinner"</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Table<span class="token punctuation">,</span> TableHead<span class="token punctuation">,</span> TableHeaderCell<span class="token punctuation">,</span> TableHeaderRow<span class="token punctuation">,</span> TableBody<span class="token punctuation">,</span> TableRow<span class="token punctuation">,</span> TableDataCell<span class="token punctuation">,</span> DefaultCellContent<span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"../../components/table"</span> <span class="token keyword">import</span> useMedusa <span class="token keyword">from</span> <span class="token string">"../../hooks/use-medusa"</span> <span class="token keyword">import</span> styled <span class="token keyword">from</span> <span class="token string">"@emotion/styled"</span> <span class="token keyword">const</span> LinkWrapper <span class="token operator">=</span> <span class="token function">styled</span><span class="token punctuation">(</span>Link<span class="token punctuation">)</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> width: 100%; height: 100%; text-decoration: none; color: black; > div { color: blue; } &:focus { outline: none; } display: flex; </span><span class="token template-punctuation string">`</span></span> <span class="token keyword">const</span> <span class="token function-variable function">TopSelling</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> products<span class="token punctuation">,</span> hasCache<span class="token punctuation">,</span> isLoading<span class="token punctuation">,</span> isReloading<span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useMedusa</span><span class="token punctuation">(</span><span class="token string">"topSelling"</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Flex flexDirection<span class="token operator">=</span><span class="token string">"column"</span> pb<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">5</span><span class="token punctuation">}</span> pt<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">5</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Flex<span class="token operator">></span> <span class="token operator"><</span>Text mb<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">3</span><span class="token punctuation">}</span> fontSize<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">20</span><span class="token punctuation">}</span> fontWeight<span class="token operator">=</span><span class="token string">"bold"</span><span class="token operator">></span> Top Selling Products <span class="token operator"><</span><span class="token operator">/</span>Text<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Flex<span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">(</span>isLoading <span class="token operator">&&</span> <span class="token operator">!</span>hasCache<span class="token punctuation">)</span> <span class="token operator">||</span> isReloading <span class="token operator">?</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Flex flexDirection<span class="token operator">=</span><span class="token string">"column"</span> alignItems<span class="token operator">=</span><span class="token string">"center"</span> height<span class="token operator">=</span><span class="token string">"100vh"</span> mt<span class="token operator">=</span><span class="token string">"20%"</span> <span class="token operator">></span> <span class="token operator"><</span>Box height<span class="token operator">=</span><span class="token string">"50px"</span> width<span class="token operator">=</span><span class="token string">"50px"</span><span class="token operator">></span> <span class="token operator"><</span>Spinner dark <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Box<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Flex<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Table<span class="token operator">></span> <span class="token operator"><</span>TableHead<span class="token operator">></span> <span class="token operator"><</span>TableHeaderRow<span class="token operator">></span> <span class="token operator"><</span>TableHeaderCell sx<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">maxWidth</span><span class="token operator">:</span> <span class="token string">"75px"</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>TableHeaderCell<span class="token operator">></span>Name<span class="token operator"><</span><span class="token operator">/</span>TableHeaderCell<span class="token operator">></span> <span class="token operator"><</span>TableHeaderCell<span class="token operator">></span>Number <span class="token keyword">of</span> Sales<span class="token operator"><</span><span class="token operator">/</span>TableHeaderCell<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>TableHeaderRow<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>TableHead<span class="token operator">></span> <span class="token operator"><</span>TableBody<span class="token operator">></span> <span class="token punctuation">{</span>products<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">p</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>TableRow key<span class="token operator">=</span><span class="token punctuation">{</span>p<span class="token punctuation">.</span>id<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>LinkWrapper to<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/a/products</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>p<span class="token punctuation">.</span>is_giftcard <span class="token operator">?</span> <span class="token string">"/gift-card"</span> <span class="token operator">:</span> <span class="token string">""</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> p<span class="token punctuation">.</span>id <span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span> <span class="token operator">></span> <span class="token operator"><</span>TableDataCell maxWidth<span class="token operator">=</span><span class="token string">"75px"</span> p<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">2</span><span class="token punctuation">}</span> height<span class="token operator">=</span><span class="token string">"100%"</span> textAlign<span class="token operator">=</span><span class="token string">"center"</span> <span class="token operator">></span> <span class="token operator"><</span>DefaultCellContent<span class="token operator">></span> <span class="token operator"><</span>Image src<span class="token operator">=</span><span class="token punctuation">{</span>p<span class="token punctuation">.</span>thumbnail <span class="token operator">||</span> ImagePlaceholder<span class="token punctuation">}</span> height<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">38</span><span class="token punctuation">}</span> width<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">38</span><span class="token punctuation">}</span> p<span class="token operator">=</span><span class="token punctuation">{</span><span class="token operator">!</span>p<span class="token punctuation">.</span>thumbnail <span class="token operator">&&</span> <span class="token string">"8px"</span><span class="token punctuation">}</span> sx<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">objectFit</span><span class="token operator">:</span> <span class="token string">"contain"</span><span class="token punctuation">,</span> <span class="token literal-property property">border</span><span class="token operator">:</span> <span class="token string">"1px solid #f1f3f5"</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>DefaultCellContent<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>TableDataCell<span class="token operator">></span> <span class="token operator"><</span>TableDataCell<span class="token operator">></span> <span class="token operator"><</span>DefaultCellContent<span class="token operator">></span><span class="token punctuation">{</span>p<span class="token punctuation">.</span>title<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>DefaultCellContent<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>TableDataCell<span class="token operator">></span> <span class="token operator"><</span>TableDataCell<span class="token operator">></span> <span class="token operator"><</span>DefaultCellContent<span class="token operator">></span> <span class="token punctuation">{</span>p<span class="token punctuation">.</span>metadata<span class="token punctuation">.</span>sales<span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>DefaultCellContent<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>TableDataCell<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>LinkWrapper<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>TableRow<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>TableBody<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Table<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Flex<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> TopSelling </code></pre></div><p>This creates the component <code class="language-text">TopSelling</code> which uses the <code class="language-text">useMedusa</code> hook to get the top selling products, then show them in a table with the image, name, and number of sales of the product.</p><p>The <code class="language-text">useMedusa</code> hook, which resides in <code class="language-text">src/hooks/use-medusa.js</code> takes as a first parameter an endpoint name. You can use any of Medusa’s default endpoints like <code class="language-text">products</code> or <code class="language-text">orders</code>. <code class="language-text">useMedusa</code> will check if the endpoint exists in <code class="language-text">src/services/api.js</code>, then, executes the request to retrieve the data.</p><p>So, in order to make sure <code class="language-text">useMedusa(</code><code class="language-text">"</code><code class="language-text">topSelling</code><code class="language-text">"</code><code class="language-text">)</code> retrieves the top selling products from the custom endpoint you created earlier, you need to add to the exported object in <code class="language-text">src/services/api.js</code> the following property at the end of it:<br/></p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"> <span class="token literal-property property">topSelling</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">list</span><span class="token punctuation">(</span><span class="token parameter">search <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> params <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>search<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">k</span> <span class="token operator">=></span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>k<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>search<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">"&"</span><span class="token punctuation">)</span> <span class="token keyword">let</span> path <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/admin/top-products</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>params <span class="token operator">&&</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">?</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>params<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span> <span class="token keyword">return</span> <span class="token function">medusaRequest</span><span class="token punctuation">(</span><span class="token string">"GET"</span><span class="token punctuation">,</span> path<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> </code></pre></div><p>This will send a <code class="language-text">GET</code> request to <code class="language-text">/admin/top-products</code> with any parameters that might be passed to the function.</p><p>The <code class="language-text">TopSelling</code> component is ready. You can now add it to the nested router in <code class="language-text">src/domain/products/index.js</code>:<br/></p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"> <span class="token keyword">const</span> <span class="token function-variable function">Products</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Router<span class="token operator">></span> <span class="token operator"><</span>ProductIndex path<span class="token operator">=</span><span class="token string">"/"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Details path<span class="token operator">=</span><span class="token string">":id"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>New path<span class="token operator">=</span><span class="token string">"new"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>TopSelling path<span class="token operator">=</span><span class="token string">"top-selling"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Router<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre></div><p>The last thing left to do is add the link in the sidebar below the <em>Products</em> link. In <code class="language-text">src/components/sidebar/index.js</code> Find the link to <em>Products</em> and add the link below it next to the <em>Collections</em> link:<br/></p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"> <span class="token operator"><</span>StyledItemContainer to<span class="token operator">=</span><span class="token string">"/a/products/top-selling"</span> activeClassName<span class="token operator">=</span><span class="token string">"active"</span> partiallyActive <span class="token operator">></span> <span class="token operator"><</span>Flex alignItems<span class="token operator">=</span><span class="token string">"center"</span> pl<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">3</span><span class="token punctuation">}</span> width<span class="token operator">=</span><span class="token string">"100%"</span><span class="token operator">></span> <span class="token operator"><</span>Text ml<span class="token operator">=</span><span class="token string">"14px"</span> variant<span class="token operator">=</span><span class="token string">"nav"</span> fontSize<span class="token operator">=</span><span class="token string">"12px"</span><span class="token operator">></span> Top Selling <span class="token operator"><</span><span class="token operator">/</span>Text<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Flex<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>StyledItemContainer<span class="token operator">></span> </code></pre></div><p>Everything is ready. Let’s try it out.</p><p>Start the backend server if it’s not started yet with the following command:<br/></p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"> <span class="token function">npm</span> start </code></pre></div><p>Then, start the server for the admin dashboard with the following command:<br/></p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"> <span class="token function">npm</span> start </code></pre></div><p>Go to the Admin panel link, which by default is <code class="language-text">localhost:7000</code> unless yours started at a different port. You will need to login with your admin credentials. By default, Medusa comes with a test admin user <code class="language-text">admin@medusa-test.com</code>with the password <code class="language-text">supersecret</code>.</p><p>Once you login, click on <em>Products</em>, and once the sidebar item expands you should see a new menu item <em>Top Selling</em>. If you click on it, a new page should open showing a table of top selling products with the number of sales for each of them.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8OglFD_q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7a1qp6ghz6uwuav974u2.png" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy"/></figure><h2 id="conclusion-and-teaser">Conclusion and teaser</h2><p>In this tutorial, you learned all the great features in the admin dashboard and how to add your own! You can utilize Medusa’s power to tackle most e-commerce use cases, and for your own unique use cases you can easily add your own features into the admin dashboard.</p><p>In the next part of the series, you’ll learn about Medusa’s storefront. You’ll create a new component on the frontend that will utilize the <code class="language-text">top-products</code>endpoint to show the user the store’s top products.</p><p>Throughout the article, I have used pictures from the current Admin Dashboard as per December, 2021. However, a redesign of the dasboard will be released in mid-January and early mock-ups and a feature walkthrough was recently released. Read more <a href="https://www.medusajs.com/post/admin-redesign">here</a>. You can see the new design below. You can also sign-up for the release of the new Admin Dashboard <a href="https://www.producthunt.com/upcoming/medusa-3">here</a>. Disclaimer: The re-design will not change any of the functionality or steps from the walkthrough above.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/s_2EA006F2E25CC90F8602DB54701EE0CCACDABD2E2B318E9CAFAB4A9487643BC2_1640010690917_Somethings-cooking-1-1.jpg" class="kg-image" alt="Get started with Medusa Part 3: Exploring our Admin Dashboard" loading="lazy" width="2000" height="1125" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/s_2EA006F2E25CC90F8602DB54701EE0CCACDABD2E2B318E9CAFAB4A9487643BC2_1640010690917_Somethings-cooking-1-1.jpg 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/s_2EA006F2E25CC90F8602DB54701EE0CCACDABD2E2B318E9CAFAB4A9487643BC2_1640010690917_Somethings-cooking-1-1.jpg 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/s_2EA006F2E25CC90F8602DB54701EE0CCACDABD2E2B318E9CAFAB4A9487643BC2_1640010690917_Somethings-cooking-1-1.jpg 1600w, https://backend.shahednasser.com/content/images/2021/12/s_2EA006F2E25CC90F8602DB54701EE0CCACDABD2E2B318E9CAFAB4A9487643BC2_1640010690917_Somethings-cooking-1-1.jpg 2400w" sizes="(min-width: 720px) 720px"/></figure>]]></content:encoded></item><item><title><![CDATA[Create Laravel Blog with Strapi v4]]></title><description><![CDATA[In this tutorial, you'll learn how to create a blog in Laravel using Strapi. The blog will have posts, tags, and allow users to post comments.]]></description><link>https://blog.shahednasser.com/create-laravel-blog-with-strapi-v4/</link><guid isPermaLink="false">Ghost__Post__61ba1908c393bb64592d848e</guid><category><![CDATA[Strapi]]></category><category><![CDATA[Laravel]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 20 Dec 2021 08:50:50 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/36dac6a27c1e3c4e16cc2c2e55053679/lum3n--RBuQ2PK_L8-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/36dac6a27c1e3c4e16cc2c2e55053679/lum3n--RBuQ2PK_L8-unsplash-2.jpg" alt="Create Laravel Blog with Strapi v4"/><p><a href="https://laravel.com">Laravel</a> is one of the most popular web frameworks that allow you to create secure and scalable websites. With Laravel, you can create almost any website, ranging from simple portfolio websites to full-fledged e-commerce solutions.</p><p><a href="https://strapi.io">Strapi</a> is a headless CMS framework that has been gaining a lot of attention. With Strapi, you can easily add CMS functionalities to your website, regardless of the technology being used. Strapi also removes the hassles of creating a database and models tailored to your CMS needs as it is customizable to the point that you can create your own models and entities, also called content types.</p><p>In this tutorial, you'll learn how to create a blog in Laravel using Strapi. The blog will have posts, tags, and allow users to post comments. You can find the code for this tutorial in <a href="https://github.com/shahednasser/strapi-laravel-blog">this GitHub repository</a>.</p><h2 id="prerequisites">Prerequisites </h2><p>Before you start, you need the following tools on your machine:</p><ol><li><a href="https://nodejs.org/en/">Node.js</a>. Only versions 12 and 14 are supported by Strapi, and 14 is recommended.</li><li><a href="https://www.php.net">PHP</a> >= v7.3</li><li><a href="https://getcomposer.org/download/">Composer</a></li></ol><p>Please note that this tutorial will be using Strapi v4 and Laravel v8.9</p><h2 id="setup-strapi">Setup Strapi</h2><p>Start by setting up Strapi. In your terminal, run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-strapi-app@latest strapi --quickstart</code></pre></div><p>Once the command is done, the server will start at <a href="http://localhost:1337">localhost:1337</a> and a new page will open in a browser. It will be a registration form, where you need to create an admin account on Strapi.</p><p>Once you're done, you'll be redirected to the main dashboard.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-15-at-7.40.33-PM.png" class="kg-image" alt="Create Laravel Blog with Strapi v4" loading="lazy" width="2000" height="1136" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-15-at-7.40.33-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-15-at-7.40.33-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-15-at-7.40.33-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/12/Screen-Shot-2021-12-15-at-7.40.33-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><h3 id="create-content-types">Create Content-Types</h3><p>Next, you'll create the content types necessary for the blog. You'll create content types for the posts and tags that the posts will use. You'll also create a comment content type which will be filled from our blog on Laravel.</p><p>Start by clicking on <em>Create your first Content type</em> in the dashboard. This will open a new page to create content types. Under the Content Types Builder sidebar, click on <em>Create new collection type </em>under Collection type. This will open a pop-up where you can enter basic and advanced settings.</p><p>You'll first create the tags content type. Enter in the Display Name field in the popup <code class="language-text">Tag</code>. This will automatically generate the singular and plural forms of the content type.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-15-at-7.45.23-PM.png" class="kg-image" alt="Create Laravel Blog with Strapi v4" loading="lazy" width="1814" height="1026" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-15-at-7.45.23-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-15-at-7.45.23-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-15-at-7.45.23-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-15-at-7.45.23-PM.png 1814w" sizes="(min-width: 720px) 720px"/></figure><p>Once you're done, click <em>Continue</em>. You can now choose the fields in this content type. tags will only have a <code class="language-text">name</code> field other than their id. So, click on the <em>Text </em>field type. Then, enter in the Name field <code class="language-text">name</code>.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-15-at-7.47.28-PM.png" class="kg-image" alt="Create Laravel Blog with Strapi v4" loading="lazy" width="1768" height="1080" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-15-at-7.47.28-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-15-at-7.47.28-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-15-at-7.47.28-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-15-at-7.47.28-PM.png 1768w" sizes="(min-width: 720px) 720px"/></figure><p>In the Advanced Settings tab, check the Required checkbox to ensure that all tags have a name. </p><p>Since that's the only field you'll add for the Tag content type, click on <em>Finish</em>. Then, when the pop-up closes, click on the<em> <em>Save</em></em> button at the top right. This will restart the server. Every time you create a content type, the server is restarted.</p><p>Next, you'll create the Post content type. Again, click on <em>Create new collection type. </em>In the pop up that opens, enter for Display Name <code class="language-text">Post</code>, then click on <em>Continue.</em></p><p>For posts, there will be fields for title, content, image, date posted, and tags that the post falls under.</p><p>For the <code class="language-text">title</code> field, choose the Text field and make it required as we did earlier. Once done, click on <em>Add another field.</em></p><p>For the <code class="language-text">content</code> field, choose the Rich text field, and make it required.</p><p>For the <code class="language-text">image</code> field, choose the Media field, and choose for Type "Single media". In the Advanced Settings tab, change the allowed file types under "Select allowed types of media" to only Images. Make the field required as well.</p><p>For the <code class="language-text">date_posted</code> field, choose the Date field, and choose for Type "datetime". Mark this field required as well.</p><p>Finally, for the <code class="language-text">tags</code> field, choose the Relation field, then for the relation type choose "Post belongs to many Tags".</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-15-at-7.59.01-PM.png" class="kg-image" alt="Create Laravel Blog with Strapi v4" loading="lazy" width="1830" height="902" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-15-at-7.59.01-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-15-at-7.59.01-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-15-at-7.59.01-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-15-at-7.59.01-PM.png 1830w" sizes="(min-width: 720px) 720px"/></figure><p>Once you're done, click on <em>Finish</em>, then click on<em> Save </em>at the top right. This will save the new content type and restart the server.</p><p>Finally, you need to create the Comment content type. Just like you did with the previous content types, create a new content type with the name <code class="language-text">Comment</code>.</p><p>The <code class="language-text">Comment</code> content type will have 3 fields. The first is an Email field with the name <code class="language-text">field</code>. Make sure to set it as required.</p><p>The second field is a Rich text field with the name <code class="language-text">content</code>. This is where the user's comment will go.</p><p>The third field is a Relation field between Comment and Post. The relation should be "Post has many Comments".</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-16-at-8.13.33-PM.png" class="kg-image" alt="Create Laravel Blog with Strapi v4" loading="lazy" width="1862" height="972" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-16-at-8.13.33-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-16-at-8.13.33-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-16-at-8.13.33-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-16-at-8.13.33-PM.png 1862w" sizes="(min-width: 720px) 720px"/></figure><p>Note that when you create this field a new field will be added automatically in Post called <code class="language-text">comments</code>.</p><p>Once you're done, click on <em>Finish</em>, then click on<em> Save </em>at the top right. This will save the new content type and restart the server.</p><p>Our content types are ready!</p><h3 id="add-content">Add Content</h3><p>The next step would be to add content. Click on <em>Content Manager</em> in the sidebar. Start by adding a few tags by clicking on <em>Tag</em> in the Content Manager sidebar, then click on <em>Add new entry</em> at the top right. </p><p>When you create content, make sure you click <em>Publish</em> after saving the content.</p><p>Next, add posts the same way. You can use <a href="https://loremipsum.io/generator/?n=5&t=p">Lorem Ipsum Generator</a> if you want to create mock content.</p><h3 id="change-permissions">Change Permissions</h3><p>The last step left is to make posts and tags public so that you can consume them in Laravel.</p><p>First, you'll create an API token to use for your requests. In the sidebar, click <em>Settings</em>, then <em>API Token</em>. Click on <em>Add Entry</em> at the top right.</p><p>In this form, enter the name of the token. This is just useful to remember what your API tokens are for. You can also enter a description.</p><p>In the Token type field, choose Full Access.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-16-at-7.27.11-PM.png" class="kg-image" alt="Create Laravel Blog with Strapi v4" loading="lazy" width="1830" height="678" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-16-at-7.27.11-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-16-at-7.27.11-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-16-at-7.27.11-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-16-at-7.27.11-PM.png 1830w" sizes="(min-width: 720px) 720px"/></figure><p>Once you're done, click on <em>Save</em> at the top right. This will create a new API token and the API token will be shown to you only once when you create it. So, copy the API token and store it somewhere as you'll use it later.</p><p>Next, you'll modify the permissions for authenticated users to be able to query content types and add new entries.</p><p>On the sidebar, click <em>Settings</em>, then <em>Roles</em> in the <em>Settings</em> sidebar.</p><p>You'll see two roles: Authenticated and Public. Click on the pencil icon on the Authenticated row.</p><p>Scroll down and you'll see that for each content type you can select what this role can access. Check Select All for Post, Tag, and Comment, then click <em>Save</em>.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-16-at-7.37.10-PM.png" class="kg-image" alt="Create Laravel Blog with Strapi v4" loading="lazy" width="964" height="1070" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-16-at-7.37.10-PM.png 600w, https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-16-at-7.37.10-PM.png 964w" sizes="(min-width: 720px) 720px"/></figure><h2 id="setup-laravel">Setup Laravel</h2><p>Now that Strapi is ready, you'll get started with Laravel.</p><p>Run the following command to create a new Laravel project:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">composer</span> create-project laravel/laravel blog</code></pre></div><p>Once this command is done, change to the directory created:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> blog</code></pre></div><p>You can then start the server with the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan serve</code></pre></div><p>This will start the server at <code class="language-text">localhost:8000</code>.</p><h3 id="add-environment-variables">Add Environment Variables</h3><p>Before you can make requests to Strapi, you need to add 2 environment variables. Add the following environment variables to <code class="language-text">.env</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">STRAPI_URL=http://localhost:1337 STRAPI_API_TOKEN=</code></pre></div><p>The first is the URL to Strapi. You can change it if it's not the same local URL. The second is the API token you created earlier. Paste it here after the <code class="language-text">=</code> sign.</p><h3 id="add-home-page">Add Home Page</h3><p>On the home page, you'll query all posts in Strapi and display them.</p><p>Run the following command in your terminal to create a new controller:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan make:controller BlogController</code></pre></div><p>Then, open <code class="language-text">app/Http/Controllers/BlogController.php</code> and the following method in the class:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">home</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//retrieve the posts from Strapi</span> <span class="token variable">$response</span> <span class="token operator">=</span> <span class="token class-name static-context">Http</span><span class="token operator">::</span><span class="token function">withToken</span><span class="token punctuation">(</span><span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'STRAPI_API_TOKEN'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'STRAPI_URL'</span><span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'/api/posts?populate=image,tags'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$posts</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$response</span><span class="token operator">-></span><span class="token function">failed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">isset</span><span class="token punctuation">(</span><span class="token variable">$data</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'error'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Server error: '</span> <span class="token operator">.</span> <span class="token variable">$data</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'error'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'message'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Request Failed'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment">//get posts from response</span> <span class="token variable">$posts</span> <span class="token operator">=</span> <span class="token variable">$response</span><span class="token operator">-></span><span class="token function">json</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'data'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'posts'</span> <span class="token operator">=></span> <span class="token variable">$posts</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>First, you query Strapi using Laravel's <a href="https://laravel.com/docs/8.x/http-client">HTTP Client</a>. You use <code class="language-text">withToken</code> to pass it the API token from <code class="language-text">.env</code> using the <code class="language-text">env</code> helper function. Then, you send a <code class="language-text">get</code> request to the endpoint <code class="language-text">localhost:1337/api/posts?populate=image,tags</code>.</p><p>Notice that <code class="language-text">localhost:1337</code> also is retrieved from <code class="language-text">.env</code>. As for the endpoint path, Strapi has a conventional path for all its content types. When querying a collection, the pattern for the endpoint is <code class="language-text">/api/{collection_name}</code>.</p><p>When you use Strapi's API, you can pass it a lot of <a href="https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html#api-parameters">useful parameters</a> that allow you to filter, sort, paginate the data, and more. Here, you use the <code class="language-text">populate</code> parameter which allows you to retrieve a content type with its relations. You use it to retrieve the post with its image and tags.</p><p>After sending the request, you can check if the request failed using <code class="language-text">$response->failed()</code>. If the request failed, you log the error. If not, you set <code class="language-text">$posts</code> to the <code class="language-text">data</code> parameter in the response body. Note that you can use the <code class="language-text">json</code> method to retrieve the parameters from a JSON response, optionally passing it a parameter name as the first element.</p><p>Next, you need to add the <code class="language-text">home</code> view. Create the file <code class="language-text">resources/views/home.blade.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span><span class="token operator">!</span><span class="token constant">DOCTYPE</span> html<span class="token operator">></span> <span class="token operator"><</span>html lang<span class="token operator">=</span><span class="token string double-quoted-string">"{{ str_replace('_', '-', app()->getLocale()) }}"</span><span class="token operator">></span> <span class="token operator"><</span>head<span class="token operator">></span> <span class="token operator"><</span>meta charset<span class="token operator">=</span><span class="token string double-quoted-string">"utf-8"</span><span class="token operator">></span> <span class="token operator"><</span>meta name<span class="token operator">=</span><span class="token string double-quoted-string">"viewport"</span> content<span class="token operator">=</span><span class="token string double-quoted-string">"width=device-width, initial-scale=1"</span><span class="token operator">></span> <span class="token operator"><</span>title<span class="token operator">></span>Blog<span class="token operator"><</span><span class="token operator">/</span>title<span class="token operator">></span> <span class="token operator"><</span>link href<span class="token operator">=</span><span class="token string double-quoted-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"</span> rel<span class="token operator">=</span><span class="token string double-quoted-string">"stylesheet"</span> integrity<span class="token operator">=</span><span class="token string double-quoted-string">"sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"</span> crossorigin<span class="token operator">=</span><span class="token string double-quoted-string">"anonymous"</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>head<span class="token operator">></span> <span class="token operator"><</span>body <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"antialiased bg-light"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"container mt-4 py-3 mx-auto bg-white rounded shadow-sm"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"row"</span><span class="token operator">></span> @<span class="token function">forelse</span> <span class="token punctuation">(</span><span class="token variable">$posts</span> <span class="token keyword">as</span> <span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"col-2 col-md-4"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card"</span><span class="token operator">></span> <span class="token operator"><</span>img src<span class="token operator">=</span><span class="token string double-quoted-string">"{{ env('STRAPI_URL') . <span class="token interpolation"><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span></span>['image']['data']['attributes']['formats']['medium']['url'] }}"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-img-top"</span> alt<span class="token operator">=</span><span class="token string double-quoted-string">"{{ <span class="token interpolation"><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span></span>['image']['data']['attributes']['alternativeText'] }}"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-body"</span><span class="token operator">></span> <span class="token operator"><</span>h5 <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-title"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'title'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>h5<span class="token operator">></span> <span class="token operator"><</span>p <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-text"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">substr</span><span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">50</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">...</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator"><</span>a href<span class="token operator">=</span><span class="token string double-quoted-string">"/post/{{ <span class="token interpolation"><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'id'</span><span class="token punctuation">]</span></span> }}"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"btn btn-primary"</span><span class="token operator">></span>Read More<span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-footer"</span><span class="token operator">></span> @<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token function">count</span><span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'tags'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'data'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> @<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'tags'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'data'</span><span class="token punctuation">]</span> <span class="token keyword">as</span> <span class="token variable">$tag</span><span class="token punctuation">)</span> <span class="token operator"><</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"badge bg-success"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$tag</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'name'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> @<span class="token keyword">endforeach</span> @<span class="token keyword">endif</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @<span class="token keyword">empty</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"col"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-body"</span><span class="token operator">></span> This is some text within a card body<span class="token operator">.</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @endforelse <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>body<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>html<span class="token operator">></span> </code></pre></div><p>This just displays the posts as <a href="https://getbootstrap.com/docs/5.1/components/card/">cards</a> using <a href="https://getbootstrap.com">Bootstrap</a>. Notice that the content type entries that Strapi return has the following format:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"data"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string">"id"</span><span class="token punctuation">,</span> <span class="token property">"attributes"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string">"title"</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>So, you'll find the content type's fields inside the <code class="language-text">attributes</code> key of <code class="language-text">data</code>.</p><p>Finally, change the current route in <code class="language-text">routes/web.php</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>BlogController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'home'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Let's test it out. Make sure that both Laravel and Strapi's servers are running. Then, open <code class="language-text">localhost:8000</code>. You'll see the posts you added as cards.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-16-at-7.48.15-PM.png" class="kg-image" alt="Create Laravel Blog with Strapi v4" loading="lazy" width="2000" height="1021" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-16-at-7.48.15-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-16-at-7.48.15-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-16-at-7.48.15-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/12/Screen-Shot-2021-12-16-at-7.48.15-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><h3 id="add-view-post-page">Add View Post Page</h3><p>Next, you'll add the page to view a post. This page receives the post ID as a parameter, then queries the post's data from Strapi.</p><p>In <code class="language-text">app/Http/Controllers/BlogController.php</code> add a new method:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">viewPost</span> <span class="token punctuation">(</span><span class="token variable">$id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//retrieve the post from Strapi</span> <span class="token variable">$response</span> <span class="token operator">=</span> <span class="token class-name static-context">Http</span><span class="token operator">::</span><span class="token function">withToken</span><span class="token punctuation">(</span><span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'STRAPI_API_TOKEN'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'STRAPI_URL'</span><span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'/api/posts/'</span> <span class="token operator">.</span> <span class="token variable">$id</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'?populate=image,tags,comments'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$response</span><span class="token operator">-></span><span class="token function">failed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">isset</span><span class="token punctuation">(</span><span class="token variable">$data</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'error'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Server error: '</span> <span class="token operator">.</span> <span class="token variable">$data</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'error'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'message'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Request Failed'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">redirectTo</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//get post from response</span> <span class="token variable">$post</span> <span class="token operator">=</span> <span class="token variable">$response</span><span class="token operator">-></span><span class="token function">json</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'data'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'post'</span> <span class="token operator">=></span> <span class="token variable">$post</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>In this method, you use the <code class="language-text">$id</code> parameter, which is the post ID, to send a request to Strapi's single entry endpoint. The endpoint's pattern is <code class="language-text">/api/{collection_name}/{id}</code>. Similar to the previous endpoint, you can also pass it parameters like <code class="language-text">populate</code>.</p><p>If the request fails, you redirect the user to the home page and log the error. If the request is done successfully, you retrieve the post from the response's body and render the view <code class="language-text">post</code>.</p><p>Now, create <code class="language-text">resources/views/post.blade.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span><span class="token operator">!</span><span class="token constant">DOCTYPE</span> html<span class="token operator">></span> <span class="token operator"><</span>html lang<span class="token operator">=</span><span class="token string double-quoted-string">"{{ str_replace('_', '-', app()->getLocale()) }}"</span><span class="token operator">></span> <span class="token operator"><</span>head<span class="token operator">></span> <span class="token operator"><</span>meta charset<span class="token operator">=</span><span class="token string double-quoted-string">"utf-8"</span><span class="token operator">></span> <span class="token operator"><</span>meta name<span class="token operator">=</span><span class="token string double-quoted-string">"viewport"</span> content<span class="token operator">=</span><span class="token string double-quoted-string">"width=device-width, initial-scale=1"</span><span class="token operator">></span> <span class="token operator"><</span>title<span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'title'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">-</span> Blog<span class="token operator"><</span><span class="token operator">/</span>title<span class="token operator">></span> <span class="token operator"><</span>link href<span class="token operator">=</span><span class="token string double-quoted-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"</span> rel<span class="token operator">=</span><span class="token string double-quoted-string">"stylesheet"</span> integrity<span class="token operator">=</span><span class="token string double-quoted-string">"sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"</span> crossorigin<span class="token operator">=</span><span class="token string double-quoted-string">"anonymous"</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>head<span class="token operator">></span> <span class="token operator"><</span>body <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"antialiased bg-light"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"container mt-4 py-3 px-5 mx-auto bg-white rounded shadow-sm"</span><span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'title'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>small <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"text-muted d-block"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'date_posted'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>small<span class="token operator">></span> <span class="token operator"><</span>img src<span class="token operator">=</span><span class="token string double-quoted-string">"{{ env('STRAPI_URL') . <span class="token interpolation"><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span></span>['image']['data']['attributes']['formats']['medium']['url'] }}"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"img-fluid mx-auto d-block my-3"</span> alt<span class="token operator">=</span><span class="token string double-quoted-string">"{{ <span class="token interpolation"><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span></span>['image']['data']['attributes']['alternativeText'] }}"</span><span class="token operator">></span> @<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token function">count</span><span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'tags'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'data'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> @<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'tags'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'data'</span><span class="token punctuation">]</span> <span class="token keyword">as</span> <span class="token variable">$tag</span><span class="token punctuation">)</span> <span class="token operator"><</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"badge bg-success"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$tag</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'name'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> @<span class="token keyword">endforeach</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @<span class="token keyword">endif</span> <span class="token operator"><</span>p <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"content"</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator"><</span>hr <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>form action<span class="token operator">=</span><span class="token string double-quoted-string">"/post/{{ <span class="token interpolation"><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'id'</span><span class="token punctuation">]</span></span> }}"</span> method<span class="token operator">=</span><span class="token string double-quoted-string">"POST"</span><span class="token operator">></span> @csrf <span class="token operator"><</span>h2<span class="token operator">></span>Add Your Comment<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-label"</span><span class="token operator">></span>Email address<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> required<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"content"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-label"</span><span class="token operator">></span>Your Comment<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>textarea rows<span class="token operator">=</span><span class="token string double-quoted-string">"5"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"content"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"content"</span> required<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>textarea<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string double-quoted-string">"submit"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"btn btn-primary"</span><span class="token operator">></span>Submit<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>body<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>html<span class="token operator">></span> </code></pre></div><p>This page just shows the post's details. Similar to how you extracted the post's data, the post's field is nested inside the <code class="language-text">attributes</code> field.</p><p>This page also has a comments form at the end of it. You'll implement its functionality after this.</p><p>Finally, add the new route in <code class="language-text">routes/web.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post/{id}'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>BlogController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'viewPost'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre></div><p>Now, open the home page again and click on <em>Read More</em> for one of the posts. A new page will open with the post's content.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-16-at-7.55.39-PM.png" class="kg-image" alt="Create Laravel Blog with Strapi v4" loading="lazy" width="2000" height="1161" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-16-at-7.55.39-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-16-at-7.55.39-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-16-at-7.55.39-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/12/Screen-Shot-2021-12-16-at-7.55.39-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>If you scroll down, you'll see a form to add your comment.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-16-at-8.10.42-PM.png" class="kg-image" alt="Create Laravel Blog with Strapi v4" loading="lazy" width="2000" height="589" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-16-at-8.10.42-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-16-at-8.10.42-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-16-at-8.10.42-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/12/Screen-Shot-2021-12-16-at-8.10.42-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><h3 id="add-comment-functionality">Add Comment Functionality</h3><p>The last thing you'll do in this tutorial is add the commenting functionality. The form is already added, so you just need to add the <code class="language-text">POST</code> route to add the comment.</p><p>Add the following method in <code class="language-text">app/Http/Controllers/BlogController.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">addComment</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token variable">$id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$data</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string double-quoted-string">"data"</span> <span class="token operator">=></span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'email'</span> <span class="token operator">=></span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'email'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'content'</span> <span class="token operator">=></span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'post'</span> <span class="token operator">=></span> <span class="token variable">$id</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token variable">$response</span> <span class="token operator">=</span> <span class="token class-name static-context">Http</span><span class="token operator">::</span><span class="token function">withToken</span><span class="token punctuation">(</span><span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'STRAPI_API_TOKEN'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">post</span><span class="token punctuation">(</span><span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'STRAPI_URL'</span><span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'/api/comments'</span><span class="token punctuation">,</span> <span class="token variable">$data</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$response</span><span class="token operator">-></span><span class="token function">failed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">isset</span><span class="token punctuation">(</span><span class="token variable">$data</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'error'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Server error: '</span> <span class="token operator">.</span> <span class="token variable">$data</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'error'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'message'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Request Failed'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">redirectTo</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//successfully added</span> <span class="token keyword">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">redirectTo</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post/'</span> <span class="token operator">.</span> <span class="token variable">$id</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>You first format the data as Strapi likes it. When adding a content type entry, you should nest the data inside a <code class="language-text">data</code> parameter. Here, you add the <code class="language-text">email</code>, <code class="language-text">content</code>, and <code class="language-text">post</code> fields. Notice that we are skipping validation here for tutorial simplicity.</p><p>Then, you send a <code class="language-text">POST</code> request to the endpoint <code class="language-text">/api/comments</code>. Strapi's endpoint pattern for adding a content type entry is <code class="language-text">/api/{collection_name}</code>. You pass the data as a second parameter to the <code class="language-text">post</code> method.</p><p>If the request fails, the user is redirected to the home page. If it's successful, the user is redirected back to the post's page.</p><p>Next, add before the comment form in <code class="language-text">resources/views/post.blade.php</code> the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>hr<span class="token operator">/</span><span class="token operator">></span> @<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">count</span><span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'comments'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'data'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"comments"</span><span class="token operator">></span> <span class="token operator"><</span>h2<span class="token operator">></span>Comments<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span> @<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'comments'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'data'</span><span class="token punctuation">]</span> <span class="token keyword">as</span> <span class="token variable">$comment</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-body"</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$comment</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-footer"</span><span class="token operator">></span> By <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$comment</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'attributes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'email'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @<span class="token keyword">endforeach</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @<span class="token keyword">endif</span></code></pre></div><p>This will show the comments if a post has any.</p><p>Finally, add the new route in <code class="language-text">routes/web.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post/{id}'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>BlogController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'addComment'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Let's test it out. Go to a post's page, then go to the comment form. Add your comment and click Submit. You'll be redirected back to the post's page, but you can see the comment below the post.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/Screen-Shot-2021-12-16-at-8.10.34-PM.png" class="kg-image" alt="Create Laravel Blog with Strapi v4" loading="lazy" width="2000" height="443" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/Screen-Shot-2021-12-16-at-8.10.34-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/Screen-Shot-2021-12-16-at-8.10.34-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/12/Screen-Shot-2021-12-16-at-8.10.34-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/12/Screen-Shot-2021-12-16-at-8.10.34-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><h2 id="conclusion">Conclusion</h2><p>In this tutorial, you learned how to build a blog with Laravel and Strapi. Strapi is completely customizable, and that simplifies the process of adding content types, adding entries, and using its endpoints to query the content types or add new entries in them.</p>]]></content:encoded></item><item><title><![CDATA[10 Reasons Why You Should Use React for Building Interactive User Interfaces]]></title><description><![CDATA[Web Page design takes time, effort, and attention to detail, but React simplifies the user interface design and developers’ lives.]]></description><link>https://blog.shahednasser.com/10-reasons-why-you-should-use-react-for-building-interactive-user-interfaces/</link><guid isPermaLink="false">Ghost__Post__61bc7669c393bb64592d8688</guid><category><![CDATA[React]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Harikrishna Kundariya]]></dc:creator><pubDate>Fri, 17 Dec 2021 12:04:36 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/be66cede7624ebbc675202ad24146138/lautaro-andreani-xkBaqlcqeb4-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/be66cede7624ebbc675202ad24146138/lautaro-andreani-xkBaqlcqeb4-unsplash-2.jpg" alt="10 Reasons Why You Should Use React for Building Interactive User Interfaces"/><p>Creating interactive end-user Interfaces is difficult regardless of the programming platform. Web Page design takes time, effort, and attention to detail, but <a href="https://reactjs.org">React</a> simplifies the user interface design and developers’ lives.</p><p>You may be curious about using React to build User Interfaces (UI). With its excellent JavaScript structure, the growth process is considerably more manageable.</p><p>Big corporations like Facebook, Airbnb, Netflix, and PayPal use it. You surely don't want to ruin your chance of creating an excellent UI for your project.</p><p>You should <a href="https://www.esparkinfo.com/web-app-development/react-js.html">hire the best React development company</a> to get your hands on highly efficient and competitive React designers.</p><h2 id="what-is-react">What is React</h2><figure class="kg-card kg-image-card"><img src="https://lh4.googleusercontent.com/hX9hG8wUHdHJ2rsqOkiQb9fPUC9R3ZQ03g2I6ljzu7iq9D03WLpedXFf6UNwg7yuYVeVf2tO6DRomV3v_Eu4ToY78tNjdE5jpoEVHm6FPmv8kKPEZy7TES0mwQabMnbMG-ghUbV2" class="kg-image" alt="10 Reasons Why You Should Use React for Building Interactive User Interfaces" loading="lazy"/></figure><p>Facebook created and maintained React, a JavaScript library. React is a practical, straightforward, and adaptable open-source JavaScript library for developing simple, quick, and scalable online apps.</p><p>React is a widely sought-after option for developing user-friendly and engaging web pages and apps that allow developers to be more creative.</p><p>What makes React so popular among businesses and brands?</p><h2 id="react-interactive-ui-features">React Interactive UI Features</h2><h3 id="simple-to-use">Simple to use</h3><p>React is easy to use and offers dynamism to any UI layout. It also enables rapid application progress with good quality, saving time for both clients and designers.</p><h3 id="declarative">Declarative</h3><p>React allows significant data changes to affect specified UI elements automatically. Because of this advanced feature, you do not need to do anything further to upgrade your UI.</p><h3 id="reusable-elements">Reusable Elements</h3><p>Reusability is a cure for developers. React offers tools and frameworks that developers may reuse to build new apps. This platform allows contrivers to reuse segments made for other apps with similar functionality. It reduces growth time and ensures faultless functioning.</p><h3 id="libraries-for-javascript-programming">Libraries for JavaScript programming</h3><p>A potent combination of JavaScript and HTML code is constantly employed, streamlining the whole coding process. The JS library has numerous methods that translate HTML elements into needed functions and simplify the overall project.</p><h3 id="assistance-with-components">Assistance with Components</h3><p>React combines JavaScript and HTML tags. Then React acts as a mediator, representing the DOM and helping decide which element needs to be changed. The HTML elements and JS codes make dealing with large amounts of data easier.</p><h3 id="seo-friendly">SEO-friendly</h3><p>Facebook put a lot of work on React. Likely the best way to construct great, SEO-friendly user experiences spanning browsers and engines.</p><h3 id="lightweight-dom-integration">Lightweight DOM integration</h3><p>Because React is so simple, it perfectly implements the DOM (document object model). It does not utilize the design but allows developers to change the DOM version in memory. This feature automatically improves application performance.</p><h3 id="expert-data-binding">Expert Data Binding</h3><p>React lags one-way data binding. It means anybody can trace all modifications made to any data section. Its simplicity is reflected here.</p><h3 id="other-benefits-of-react">Other Benefits of React</h3><ul><li>Facilitates coding of JavaScript</li><li>Outstanding cross-platform support</li><li>Manages dependencies</li><li>Easy template design</li><li>UI-driven designs</li><li>Simple to adopt</li></ul><h2 id="ten-reasons-to-use-react-in-your-project">Ten Reasons to Use React in Your Project</h2><p>If you've heard of React but aren't sure whether to utilize it in your project, here are the top ten reasons why React could be the best choice.</p><h3 id="1-it-is-simple-to-learn">1. It is simple to learn.</h3><p>Unlike Angular and Vue, React is considerably easier to understand. It's one of the critical reasons React proliferated. It helps firms construct projects rapidly. The more challenging technology or structure is to comprehend, the lengthier it takes to develop. And we humans prefer to shun complex tasks. However, because React is a straightforward platform, enterprises and major brands are more tempted to use it.</p><h3 id="2-creating-rich-user-interfaces">2. Creating rich user interfaces</h3><p>The UI of a program is critical nowadays. A poorly designed UI reduces an application's chances of success. However, a high-quality UI increases the likelihood of people using your program. So, creating rich end-UIs is crucial for a program to exist. The helpful information is that React's declarative elements allow us to construct high-quality, rich UXs.</p><h3 id="3-it-supports-custom-components">3. It supports custom components</h3><p>JSX, a voluntary semantic extension, allows you to design your elements for React. These elements allow HTML quoting and make subcomponent rendering easy for contrivers. JSX is already used to design bespoke elements, construct high-volume apps, and transform HTML mock-ups into ReactElement trees.</p><h3 id="4-it-boosts-developers-output">4. It boosts developers' output</h3><p>Frequent updates can pose problems with complex logic since a single move might substantially affect other aspects. Facebook fixed the issue by making React's elements reusable. Reusable elements allow formulators to reuse digital materials. It's also simple to add essential components like keys, input fields, and a checkbox to wrapper elements, which will then be moved to the root component. Because each element in React has its internal logic quickly changed, this strategy increases application growth productivity.</p><h3 id="5-it-provides-quick-rendering">5. It provides quick rendering</h3><p>Defining the app's structure early in the design process is crucial. The DOM model is, in a nutshell, a tree-structured model. Slight UI changes at higher levels might have significant consequences. A virtual DOM created by Facebook can address such differences. As its name indicates, the virtual DOM is a virtual representation that allows testing and evaluating risks before making any changes. Faster app performance and a better UX.</p><h3 id="6-its-search-engine-optimized">6. It's search engine optimized.</h3><p>SEO is the key to any internet business's success. Google favors apps that load quickly and render quickly. React's quick rendering minimizes webpage load time compared to other platforms, which helps businesses rank higher on Google Search Engine Result Pages.</p><h3 id="7-it-includes-a-growth-toolbox">7. It includes a growth toolbox</h3><p>Incorporating new technology into projects may be enjoyable and helpful, but only when done correctly. Facebook recognizes this and has introduced much-needed React and Chrome dev tools to its React structure. These React tools let designers find the child and parent elements, investigate components' hierarchical structures, and examine elements' states and properties.</p><h3 id="8-supportive-community">8. Supportive community</h3><p>One of the advantages of utilizing React, like Angular, is the strong community. Every day, thousands of React designers improve the web platform. The project has 136,079 stars and 1,331 regular patrons, at the time of writing this. Experts often provide unlimited React tutorial videos and in-depth React papers and blogs. Also, React experts frequently answer questions on QA sites, so you can always receive professional help.</p><h3 id="9-it-improves-code-stability">9. It improves code stability</h3><p>React ensures that changes in the child structure do not impact the parent structure. So, if a designer modifies an object, they need to edit its states. They will upgrade only one element. This flow of data and architecture improves the code's stability and the application's pace.</p><h3 id="10-numerous-fortune-500-companies-use-it">10. Numerous Fortune 500 companies use it.</h3><p>Still undecided about React?</p><p>Check out some instances of React solutions that are inspiring. Many Fortune 500 organizations use React for their web pages and mobile apps. Several high-profile firms use the React framework, including Netflix, PayPal, the BBC, Lyft, and the Times New York, to cite just a few. Tencent QQ, Walmart, Tesla, and Airbnb are just a few well-known companies that have used the React structure in their mobile applications. To put it simply, React is a convenient web and mobile app growth platform.</p><h2 id="conclusion">Conclusion</h2><p>Now that you know the benefits and best practices of React, you can see why it is an excellent framework. Large and mid-sized businesses alike are using React to create their web pages' UIs, which should come as no surprise.</p>]]></content:encoded></item><item><title><![CDATA[React Native Navigation Tutorial]]></title><description><![CDATA[In this tutorial, you'll learn how to use React Navigation in your React Native app.]]></description><link>https://blog.shahednasser.com/react-native-navigation-tutorial/</link><guid isPermaLink="false">Ghost__Post__61b1cb7ad752820612f17bad</guid><category><![CDATA[React Native]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 09 Dec 2021 13:38:31 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/de081a39f1737345436f7c509de3f888/nathan-da-silva-FO7kUmBYVi0-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/de081a39f1737345436f7c509de3f888/nathan-da-silva-FO7kUmBYVi0-unsplash-2.jpg" alt="React Native Navigation Tutorial"/><p><a href="https://reactnative.dev">React Native</a> is one of the most popular cross-platform app development frameworks. Using JavaScript, you can develop native apps for both Android and iOS.</p><p>One important part of creating apps is being able to navigate between screens. In this tutorial, you'll learn how to use <a href="https://reactnavigation.org">React Navigation</a> in your app to add navigation. This will include basic navigation from one screen to another, going back to the previous screen, passing parameters, listening to events, and more.</p><p>This tutorial will not explain the basics of creating a React Native app. If you're interested in learning about that, you can check out my other tutorial <a href="https://blog.shahednasser.com/react-native-tutorial-create-your-first-app">React Native Tutorial: Create Your First App</a>.</p><p>You can find the code for this tutorial on <a href="https://github.com/shahednasser/react-navigation-tutorial">this GitHub repository</a>.</p><h2 id="prerequisites">Prerequisites </h2><p>Make sure you have both <a href="https://nodejs.org/en/">Node.js</a> and NPM installed on your machine. You can check if they're installed with the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">node</span> -v <span class="token function">npm</span> -v</code></pre></div><p>If they're not installed, you can <a href="https://nodejs.org/en/">install Node.js</a> and NPM will be installed automatically with it.</p><p> After that, make sure you install <a href="https://expo.dev">Expo</a>'s CLI if you don't have it installed:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> -g expo-cli</code></pre></div><p>If you're not familiar with what Expo is, Expo provides a set of tools built around React. Most importantly, it allows you to write and build your React Native app in minutes.</p><p>You should also install <a href="https://expo.dev/client">Expo Go</a> on your device to be able to test the app as we go through the tutorial.</p><h2 id="project-setup">Project Setup</h2><p>Start by creating a new React Native project using Expo's CLI:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">expo init react-navigation-tutorial —npm</code></pre></div><p>You'll be then prompted to choose the type of app, choose "blank".</p><p>After that the <code class="language-text">init</code> command will install the dependencies you need for your React Native project.</p><p>Once it's done, change to the directory of the project:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> react-navigation-tutorial</code></pre></div><p>Now, you'll install the dependencies required to use React Navigation. First, install the building blocks libraries using Expo's CLI with the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">expo <span class="token function">install</span> react-native-screens react-native-safe-area-context</code></pre></div><p>Second, install the native stack navigator library:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> @react-navigation/native-stack</code></pre></div><p>Now, you have all the libraries required to start using React Navigation.</p><p>Finally, install <a href="https://callstack.github.io/react-native-paper/index.html">React Native Paper</a> to have beautifully-styled components in your app:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> react-native-paper</code></pre></div><h2 id="set-up-react-navigation">Set Up React Navigation</h2><p>Before you can start adding routes to your app, you need to create a Stack Navigator. This stack navigator will be used to create screens and navigate between them.</p><p>In <code class="language-text">App.js</code>, change the content to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> NavigationContainer <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@react-navigation/native'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> createNativeStackNavigator <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@react-navigation/native-stack'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Provider <span class="token keyword">as</span> PaperProvider <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-paper'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> HomeScreen <span class="token keyword">from</span> <span class="token string">'./screens/HomeScreen'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> Stack <span class="token operator">=</span> <span class="token function">createNativeStackNavigator</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>PaperProvider<span class="token operator">></span> <span class="token operator"><</span>NavigationContainer<span class="token operator">></span> <span class="token operator"><</span>Stack<span class="token punctuation">.</span>Navigator<span class="token operator">></span> <span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Home"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>HomeScreen<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Stack<span class="token punctuation">.</span>Navigator<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>NavigationContainer<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>PaperProvider<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre></div><p>Notice that in the returned value of <code class="language-text">App</code>, you first have <code class="language-text"><PaperProvider></code> at the top of the elements. This is just used to make sure all screens share the same theme.</p><p>Next, you have the <code class="language-text"><NavigationContainer></code>. This component manages the navigation tree and contains the navigation state. So, it should wrap Stack navigators.</p><p>Inside <code class="language-text"><NavigationContainer></code> you have <code class="language-text"><Stack.Navigator></code>. <code class="language-text">Stack</code> is created using <code class="language-text">createNativeStackNavigator</code>. This function returns an object containing 2 properties: <code class="language-text">Screen</code> and <code class="language-text">Navigator</code>. The <code class="language-text">Navigator</code> property is a React element and it should be used to wrap the <code class="language-text">Screen</code> elements to manage routing configurations.</p><p>So, inside <code class="language-text"><Stack.Navigator></code> you'll have one or more <code class="language-text"><Stack.Screen></code> components. For each route, you'll have a <code class="language-text"><Stack.Screen></code> component. Now, you just have one component that points to the <code class="language-text">Home</code> route.</p><p>Notice that a <code class="language-text">Screen</code> component takes the <code class="language-text">name</code> prop, which is the name of the route and will be referenced later on when navigating to this route, and the <code class="language-text">component</code> property which is the component to render for this route.</p><p>As you can see, you're passing <code class="language-text">HomeScreen</code> component to the <code class="language-text">Home</code> route, so you need to create it now.</p><p>Create the directory <code class="language-text">screens</code>, and inside that directory create a new file <code class="language-text">HomeScreen.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> ScrollView<span class="token punctuation">,</span> StyleSheet <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button<span class="token punctuation">,</span> Card <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-paper'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> DefaultTheme <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-paper'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">HomeScreen</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>ScrollView style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>scrollView<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>card<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Title title<span class="token operator">=</span><span class="token string">"Home Screen"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>ScrollView<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> styles <span class="token operator">=</span> StyleSheet<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">scrollView</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">backgroundColor</span><span class="token operator">:</span> DefaultTheme<span class="token punctuation">.</span>colors<span class="token punctuation">.</span>background<span class="token punctuation">,</span> <span class="token literal-property property">paddingTop</span><span class="token operator">:</span> <span class="token number">10</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">card</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'90%'</span><span class="token punctuation">,</span> <span class="token literal-property property">marginLeft</span><span class="token operator">:</span> <span class="token string">'auto'</span><span class="token punctuation">,</span> <span class="token literal-property property">marginRight</span><span class="token operator">:</span> <span class="token string">'auto'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> HomeScreen</code></pre></div><p>This will create a basic home screen with a <a href="https://reactnative.dev/docs/scrollview">ScrollView</a> component containing a <a href="https://callstack.github.io/react-native-paper/card.html">Card</a> component with the title "Home Screen".</p><p>You just created your first route with React Navigation! Let's test it out.</p><p>In your terminal run to start your app:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>Then, you'll be able to run the app on Expo Go on your phone by scanning the QR code on the Expo Go app on Android or on the Camera app on iOS.</p><p>Once the app run, you'll see the Home screen that you created as it's the default and only route.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/IMG_1545.PNG" class="kg-image" alt="React Native Navigation Tutorial" loading="lazy" width="1170" height="2532" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/IMG_1545.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/IMG_1545.PNG 1000w, https://backend.shahednasser.com/content/images/2021/12/IMG_1545.PNG 1170w" sizes="(min-width: 720px) 720px"/></figure><h2 id="navigate-to-another-screen">Navigate to Another Screen</h2><p>In this section, you'll learn how to navigate from one screen to another.</p><p>Screens that are inside the Stack Navigation, like HomeScreen in this app, receive a <code class="language-text">navigation</code> prop. This prop allows us to navigate to other screens in the app.</p><p>Let's first create the screen you'll navigate to. Create the file <code class="language-text">screens/BookScreen.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> StyleSheet<span class="token punctuation">,</span> View <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Card <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-paper'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> DefaultTheme <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-paper'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">BookScreen</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>View style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>container<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>card<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Title title<span class="token operator">=</span><span class="token string">"This is Books Screen"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>View<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> styles <span class="token operator">=</span> StyleSheet<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">container</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">flex</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">flexDirection</span><span class="token operator">:</span> <span class="token string">'column'</span><span class="token punctuation">,</span> <span class="token literal-property property">backgroundColor</span><span class="token operator">:</span> DefaultTheme<span class="token punctuation">.</span>colors<span class="token punctuation">.</span>background<span class="token punctuation">,</span> <span class="token literal-property property">alignItems</span><span class="token operator">:</span> <span class="token string">'center'</span><span class="token punctuation">,</span> <span class="token literal-property property">paddingTop</span><span class="token operator">:</span> <span class="token number">10</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">card</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'90%'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> BookScreen<span class="token punctuation">;</span></code></pre></div><p>This screen is similar to <code class="language-text">HomeScreen</code>. It just shows a card with the title "This is Books Screen".</p><p>Next, add the new route in <code class="language-text">App.js</code> for <code class="language-text">BookScreen</code> below the "Home" route:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Book"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>BookScreen<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>Don't forget to import <code class="language-text">BookScreen</code> below the imports at the beginning of <code class="language-text">App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> BookScreen <span class="token keyword">from</span> <span class="token string">'./screens/BookScreen'</span><span class="token punctuation">;</span></code></pre></div><p>Now, you can navigate to the "Book" route inside this stack navigation. To see how it works, you'll add a button in <code class="language-text">HomeScreen</code> that when the user clicks will navigate to <code class="language-text">BookScreen</code>.</p><p>In <code class="language-text">HomeScreen</code>, add the <code class="language-text">navigation</code> prop to the function:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">HomeScreen</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> navigation <span class="token punctuation">}</span></span><span class="token punctuation">)</span></code></pre></div><p>Then, change the returned value of the function to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>ScrollView style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>scrollView<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>card<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Title title<span class="token operator">=</span><span class="token string">"Navigate to 'Book' Screen"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Content<span class="token operator">></span> <span class="token operator"><</span>Button mode<span class="token operator">=</span><span class="token string">"contained"</span> onPress<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> navigation<span class="token punctuation">.</span><span class="token function">navigate</span><span class="token punctuation">(</span><span class="token string">'Book'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span> Navigate <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token punctuation">.</span>Content<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>ScrollView<span class="token operator">></span> <span class="token punctuation">)</span></code></pre></div><p>You change the title of the card to "Navigate to 'Book' Screen". Then, inside the content of the card, you add a <a href="https://callstack.github.io/react-native-paper/button.html">Button</a> component with <code class="language-text">onPress</code> listener. This listener will be executed when the user presses on the button.</p><p>Inside the listener, you use the <code class="language-text">navigation</code> prop to navigate to the <code class="language-text">Book</code> screen using the method <code class="language-text">navigate</code>. The method <code class="language-text">navigate</code> takes the name of the route to navigate to.</p><p>Let's test it out. Run the app again if it isn't running. You should see a new button on the Home screen.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/IMG_1543.PNG" class="kg-image" alt="React Native Navigation Tutorial" loading="lazy" width="1170" height="2532" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/IMG_1543.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/IMG_1543.PNG 1000w, https://backend.shahednasser.com/content/images/2021/12/IMG_1543.PNG 1170w" sizes="(min-width: 720px) 720px"/></figure><p>Try clicking on the <code class="language-text">Navigate</code> button. You'll be navigated to the <code class="language-text">BookScreen</code>.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/IMG_1544.PNG" class="kg-image" alt="React Native Navigation Tutorial" loading="lazy" width="1170" height="2532" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/IMG_1544.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/IMG_1544.PNG 1000w, https://backend.shahednasser.com/content/images/2021/12/IMG_1544.PNG 1170w" sizes="(min-width: 720px) 720px"/></figure><p>Notice how the back button in the navigation bar is added automatically when you navigate to another screen. You can use it to go back to the previous screen, which is in this case the Home screen.</p><h2 id="navigate-with-parameters">Navigate with Parameters</h2><p>In a lot of cases, you'll need to navigate to another screen and pass it parameters. In this section, you'll create an input that allows the user to enter their name, then when they submit you'll open a new screen called <code class="language-text">NameScreen</code> which will show a greeting to the user with the name they entered.</p><p>Start by adding a new state variable to hold the value of the input you'll add soon in <code class="language-text">HomeScreen.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>name<span class="token punctuation">,</span> setName<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Make sure to add an import for <code class="language-text">useState</code> at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span></code></pre></div><p>Then, add a new Card component below the existing one:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Card style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>card<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Title title<span class="token operator">=</span><span class="token string">"Navigate with Parameters"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Content<span class="token operator">></span> <span class="token operator"><</span>TextInput mode<span class="token operator">=</span><span class="token string">"outlined"</span> label<span class="token operator">=</span><span class="token string">"Name"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>name<span class="token punctuation">}</span> onChangeText<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">text</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setName</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token punctuation">}</span> style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>textInput<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Button mode<span class="token operator">=</span><span class="token string">"contained"</span> disabled<span class="token operator">=</span><span class="token punctuation">{</span>name<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">}</span> onPress<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> navigation<span class="token punctuation">.</span><span class="token function">navigate</span><span class="token punctuation">(</span><span class="token string">'Name'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span> Navigate <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token punctuation">.</span>Content<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token operator">></span></code></pre></div><p>This new card has a <a href="https://callstack.github.io/react-native-paper/text-input.html">TextInput</a> with the value <code class="language-text">name</code>, and on the <code class="language-text">onChangeText</code> event, which occurs when the user makes changes to the text inside the input, you change the value of the <code class="language-text">name</code> state variable.</p><p>Below the input, you have a button that is disabled when the <code class="language-text">name</code> state variable is empty. You also add an <code class="language-text">onPress</code> event listener which navigates the user to the <code class="language-text">Name</code> route. </p><p>Notice that you're using the same <code class="language-text">navigation.navigate</code> method that you used before to navigate to the "Book" route, however, this time you pass a second parameter to the method. This method accepts as a second parameter an object of parameters you want to pass. Here, you pass the <code class="language-text">name</code> variable inside the object.</p><p>One last thing you need to do in the <code class="language-text">HomeScreen</code> is change the <code class="language-text">styles</code> object to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> styles <span class="token operator">=</span> StyleSheet<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">scrollView</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">backgroundColor</span><span class="token operator">:</span> DefaultTheme<span class="token punctuation">.</span>colors<span class="token punctuation">.</span>background<span class="token punctuation">,</span> <span class="token literal-property property">paddingTop</span><span class="token operator">:</span> <span class="token number">10</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">card</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'90%'</span><span class="token punctuation">,</span> <span class="token literal-property property">marginLeft</span><span class="token operator">:</span> <span class="token string">'auto'</span><span class="token punctuation">,</span> <span class="token literal-property property">marginRight</span><span class="token operator">:</span> <span class="token string">'auto'</span><span class="token punctuation">,</span> <span class="token literal-property property">marginBottom</span><span class="token operator">:</span> <span class="token number">10</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">textInput</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">marginBottom</span><span class="token operator">:</span> <span class="token number">10</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This just makes some changes to the <code class="language-text">card</code> property and adds a new property <code class="language-text">textInput</code>.</p><p>You'll now create the <code class="language-text">NameScreen</code> which will be the component for the "Name" route you'll add soon. Create <code class="language-text">screens/NameScreen.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> StyleSheet<span class="token punctuation">,</span> View <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Card <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-paper'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> DefaultTheme <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-paper'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">NameScreen</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> route <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span> <span class="token operator">=</span> route<span class="token punctuation">.</span>params<span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>View style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>container<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>card<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Title title<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Hello, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>View<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> styles <span class="token operator">=</span> StyleSheet<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">container</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">flex</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">flexDirection</span><span class="token operator">:</span> <span class="token string">'column'</span><span class="token punctuation">,</span> <span class="token literal-property property">backgroundColor</span><span class="token operator">:</span> DefaultTheme<span class="token punctuation">.</span>colors<span class="token punctuation">.</span>background<span class="token punctuation">,</span> <span class="token literal-property property">alignItems</span><span class="token operator">:</span> <span class="token string">'center'</span><span class="token punctuation">,</span> <span class="token literal-property property">paddingTop</span><span class="token operator">:</span> <span class="token number">10</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">card</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'90%'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> NameScreen<span class="token punctuation">;</span></code></pre></div><p>This screen is essentially the same as <code class="language-text">BookScreen</code>, however, notice the <code class="language-text">route</code> prop passed to the function.</p><p>As mentioned before, the components inside the navigation stack receive a <code class="language-text">navigation</code> prop to navigate between screens. They also receive a <code class="language-text">route</code> prop which you can use to get the parameters passed to the screen using <code class="language-text">route.params</code>.</p><p>So, in <code class="language-text">NameScreen</code>, you retrieve the value entered in the <code class="language-text">Name</code> input in the <code class="language-text">HomeScreen</code>, which is passed when navigating to the <code class="language-text">NameScreen</code> when the button is clicked using <code class="language-text">route.params</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span> <span class="token operator">=</span> route<span class="token punctuation">.</span>params<span class="token punctuation">;</span></code></pre></div><p>You then show the user a greeting inside a card using the name parameter.</p><p>One last thing left to do is add the "Name" route to the navigation stack. Add a new <code class="language-text"><Stack.Screen></code> below the previous ones in <code class="language-text">App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Name"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>NameScreen<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>And import <code class="language-text">NameScreen</code> below other imports at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> NameScreen <span class="token keyword">from</span> <span class="token string">'./screens/NameScreen'</span><span class="token punctuation">;</span></code></pre></div><p>Let's test it out. Run the app if it isn't already running. You'll see that there's a new card on the Home screen with an input and a button.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/IMG_1546.PNG" class="kg-image" alt="React Native Navigation Tutorial" loading="lazy" width="1170" height="2532" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/IMG_1546.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/IMG_1546.PNG 1000w, https://backend.shahednasser.com/content/images/2021/12/IMG_1546.PNG 1170w" sizes="(min-width: 720px) 720px"/></figure><p>Try entering your name, then click the "Navigate" button below the input. You'll be navigated to the <code class="language-text">NameScreen</code> and you'll see your name.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/IMG_1547.PNG" class="kg-image" alt="React Native Navigation Tutorial" loading="lazy" width="1170" height="2532" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/IMG_1547.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/IMG_1547.PNG 1000w, https://backend.shahednasser.com/content/images/2021/12/IMG_1547.PNG 1170w" sizes="(min-width: 720px) 720px"/></figure><p>You can try going back then changing the value of the name. The name in the <code class="language-text">NameScreen</code> will change accordingly.</p><h2 id="configure-the-header">Configure the Header</h2><h3 id="change-the-title">Change the title</h3><p>Sometimes, you want the title of a route to be different than the name of the route, or you want the title to be dynamic based on a parameter passed or some other logic.</p><p>In this section, you'll add a new input in <code class="language-text">HomeScreen</code> that will let you to enter a title, then on clicking the navigate button you'll be navigated to a new screen <code class="language-text">TitleScreen</code>, whose title will change based on the title entered in the input in HomeScreen.</p><p>Start by adding a new state variable in <code class="language-text">HomeScreen.js</code> to store the title:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>title<span class="token punctuation">,</span> setTitle<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Then, add a new card below the previous cards:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Card style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>card<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Title title<span class="token operator">=</span><span class="token string">"Navigate to Route with Title"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Content<span class="token operator">></span> <span class="token operator"><</span>TextInput mode<span class="token operator">=</span><span class="token string">"outlined"</span> label<span class="token operator">=</span><span class="token string">"Title"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>title<span class="token punctuation">}</span> onChangeText<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">text</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setTitle</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token punctuation">}</span> style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>textInput<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Button mode<span class="token operator">=</span><span class="token string">"contained"</span> disabled<span class="token operator">=</span><span class="token punctuation">{</span>title<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">}</span> onPress<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> navigation<span class="token punctuation">.</span><span class="token function">navigate</span><span class="token punctuation">(</span><span class="token string">'Title'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> title <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span> Navigate <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token punctuation">.</span>Content<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token operator">></span></code></pre></div><p>This is pretty much the same as the card we added in the previous section. The only difference is that it uses the <code class="language-text">title</code> state variable, and the listener for <code class="language-text">onPress</code> for the button navigates to the route "Title", passing the <code class="language-text">title</code> as a parameter.</p><p>Next, create the file <code class="language-text">screens/Title.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> StyleSheet<span class="token punctuation">,</span> View <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Card <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-paper'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> DefaultTheme <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-paper'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">TitleScreen</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>View style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>container<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>card<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Title title<span class="token operator">=</span><span class="token string">"This is title screen"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>View<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> styles <span class="token operator">=</span> StyleSheet<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">container</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">flex</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">flexDirection</span><span class="token operator">:</span> <span class="token string">'column'</span><span class="token punctuation">,</span> <span class="token literal-property property">backgroundColor</span><span class="token operator">:</span> DefaultTheme<span class="token punctuation">.</span>colors<span class="token punctuation">.</span>background<span class="token punctuation">,</span> <span class="token literal-property property">alignItems</span><span class="token operator">:</span> <span class="token string">'center'</span><span class="token punctuation">,</span> <span class="token literal-property property">paddingTop</span><span class="token operator">:</span> <span class="token number">10</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">card</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'90%'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> TitleScreen<span class="token punctuation">;</span></code></pre></div><p>This screen has nothing special. It just shows a card with the title "This is title screen". It doesn't even use the title parameter.</p><p>That's because you can change the title of a screen by passing an <code class="language-text">options</code> parameter to <code class="language-text"><Stack.Screen></code> when adding the route.</p><p>In <code class="language-text">App.js</code>, add an import for <code class="language-text">TitleScreen</code> below other imports at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> TitleScreen <span class="token keyword">from</span> <span class="token string">'./screens/TitleScreen'</span><span class="token punctuation">;</span></code></pre></div><p>Then, add the new route below previous <code class="language-text"><Stack.Screen></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Title"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>TitleScreen<span class="token punctuation">}</span> options<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>route<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">title</span><span class="token operator">:</span> route<span class="token punctuation">.</span>params<span class="token punctuation">.</span>title<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>Every <code class="language-text">Stack.Screen</code> component can take an <code class="language-text">options</code> prop. The <code class="language-text">options</code> prop can be an object like so:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">options<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">"Hello"</span><span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre></div><p>This is enough if your options are static. However, if the value for any of the options is dynamic, like in this example, you can instead pass it a function that returns an object. This function can receive as a parameter <code class="language-text">route</code>, which is similar to the <code class="language-text">route</code> parameter you used in <code class="language-text">NameScreen</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">options<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>route<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">title</span><span class="token operator">:</span> route<span class="token punctuation">.</span>params<span class="token punctuation">.</span>title<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span></code></pre></div><p>In this function, you return an object that has a <code class="language-text">title</code> property with the value <code class="language-text">route.params.title</code>. So, when the user enters a title in the input and clicks on the Navigate button, the title will be passed to the route, which will change the title of "Title" route using the function passed to the <code class="language-text">options</code> prop.</p><p>Let's test it out. Run the app if it's not running already. You should see a new card on the Home screen with a new input:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/IMG_1548.PNG" class="kg-image" alt="React Native Navigation Tutorial" loading="lazy" width="1170" height="2532" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/IMG_1548.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/IMG_1548.PNG 1000w, https://backend.shahednasser.com/content/images/2021/12/IMG_1548.PNG 1170w" sizes="(min-width: 720px) 720px"/></figure><p>Try entering any title you want in the input then click on Navigate. You'll see that you'll be navigated to the <code class="language-text">TitleScreen</code>, but the title will be the value you entered in the input.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/IMG_1549.PNG" class="kg-image" alt="React Native Navigation Tutorial" loading="lazy" width="1170" height="2532" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/IMG_1549.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/IMG_1549.PNG 1000w, https://backend.shahednasser.com/content/images/2021/12/IMG_1549.PNG 1170w" sizes="(min-width: 720px) 720px"/></figure><p>You can try going back then changing the value entered in the input. The title of the screen will change accordingly.</p><h3 id="add-header-button">Add Header Button</h3><p>Another option you can add is header buttons. You can customize what your header shows on the left and right by using the <code class="language-text">headerRight</code> and <code class="language-text">headerLeft</code> properties in the <code class="language-text">options</code> param of <code class="language-text"><Stack.Screen></code>.</p><p>In this section, you'll add a button to the right of the header of the Home screen which will show a user an alert when they click on it.</p><p>In <code class="language-text">App.js</code>, add to the "Home" route a prop <code class="language-text">option</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Home"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>HomeScreen<span class="token punctuation">}</span> options<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function-variable function">headerRight</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>IconButton icon<span class="token operator">=</span><span class="token string">"alert-outline"</span> onPress<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'You\'re awesome!'</span><span class="token punctuation">)</span><span class="token punctuation">}</span> color<span class="token operator">=</span><span class="token punctuation">{</span>DefaultTheme<span class="token punctuation">.</span>colors<span class="token punctuation">.</span>notification<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>In the <code class="language-text">options</code> prop, you pass an object with the property <code class="language-text">headerRight</code>. The <code class="language-text">headerRight</code> property can be a component that you can render elements inside. You render an <a href="https://callstack.github.io/react-native-paper/icon-button.html">IconButton</a> component, which is a button that only has an icon without text. In the <code class="language-text">onPress</code> event listener, you show an alert to the user.</p><p>That's all. Run the app if it isn't running already. You'll see a new icon at the top right of the header in Home Screen.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/IMG_1550.PNG" class="kg-image" alt="React Native Navigation Tutorial" loading="lazy" width="1170" height="2532" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/IMG_1550.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/IMG_1550.PNG 1000w, https://backend.shahednasser.com/content/images/2021/12/IMG_1550.PNG 1170w" sizes="(min-width: 720px) 720px"/></figure><p>Click on it and you'll see an alert.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/IMG_1551.PNG" class="kg-image" alt="React Native Navigation Tutorial" loading="lazy" width="1170" height="2532" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/IMG_1551.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/IMG_1551.PNG 1000w, https://backend.shahednasser.com/content/images/2021/12/IMG_1551.PNG 1170w" sizes="(min-width: 720px) 720px"/></figure><h2 id="navigation-events">Navigation Events</h2><p>In React Navigation, you can subscribe to two events: <code class="language-text">focus</code> and <code class="language-text">blur</code>. The <code class="language-text">focus</code> event will occur every time the screen is opened and is currently the main screen. The <code class="language-text">blur</code> event will occur whenever a screen was in focus but navigation occurs that makes the screen not the current main screen. Simply put, the <code class="language-text">focus</code> event is when the screen is visible to the user, and the <code class="language-text">blur</code> event occurs when a screen was visible to a user but isn't anymore. </p><p>In this section, you'll add a counter that will count how many times you navigated to other screens from the home screen. So, this counter will increment in the <code class="language-text">blur</code> event.</p><p>To subscribe to events, in a <code class="language-text">useEffect</code> callback inside a component, you can use <code class="language-text">navigation.addListener</code> passing it the name of the event as a first parameter, and the event handler as a second parameter. The <code class="language-text">addListener</code> method returns an unsubscribe function which you should return in the <code class="language-text">useEffect</code> callback.</p><p>In <code class="language-text">HomeScreen.js</code>, add an import for <code class="language-text">useEffect</code> at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useEffect<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span></code></pre></div><p>Then, add a new state variable <code class="language-text">counter</code> inside the <code class="language-text">HomeScreen</code> component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>counter<span class="token punctuation">,</span> setCounter<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>After that add the <code class="language-text">useEffect</code> callback that will register the event handle for the <code class="language-text">blur</code> event:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> navigation<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token string">'blur'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setCounter</span><span class="token punctuation">(</span>counter <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>As you can see, you use <code class="language-text">navigation.addListener</code> to add an event listener to the <code class="language-text">blur</code> event. The function passed as a second parameter is the handler of the event. It will be executed whenever the screen is out of focus (not the screen visible to the user). Inside the event handler, you increment the counter by 1.</p><p>Finally, you'll show the counter at the top of the screen. In <code class="language-text">ScrollView</code>, add a new card before the previously added cards:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Card style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>card<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Title title<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Navigation Count: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>counter<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token operator">></span></code></pre></div><p>Let's test it out. Run the app if it's not already running. You should see a card with a count of navigation at the top of the screen.</p><h2 id="go-back">Go Back</h2><p>The last thing you'll learn in this tutorial is how to go back to the previous screen. As you've seen throughout the tutorial, when you navigate to a screen you'll see a back button in the header which you can use to go back to the previous screen.</p><p>Although this is sufficient in most cases, sometimes you want to go back to the previous screen programmatically. You'll create in this section a new screen <code class="language-text">BackScreen</code> which you can go to from the <code class="language-text">HomeScreen</code>. This screen will have a back button in its content and when you click on it you can go back to the previous screen, which is the <code class="language-text">HomeScreen</code>.</p><p>Create the file <code class="language-text">screens/BackScreen.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> StyleSheet<span class="token punctuation">,</span> View <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button<span class="token punctuation">,</span> Card <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-paper'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> DefaultTheme <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-paper'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">BackScreen</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> navigation <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>View style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>container<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>card<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Title title<span class="token operator">=</span><span class="token string">"This is Back Screen"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Content<span class="token operator">></span> <span class="token operator"><</span>Button mode<span class="token operator">=</span><span class="token string">"contained"</span> onPress<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> navigation<span class="token punctuation">.</span><span class="token function">goBack</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span> Go Back <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token punctuation">.</span>Content<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>View<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> styles <span class="token operator">=</span> StyleSheet<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">container</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">flex</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">flexDirection</span><span class="token operator">:</span> <span class="token string">'column'</span><span class="token punctuation">,</span> <span class="token literal-property property">backgroundColor</span><span class="token operator">:</span> DefaultTheme<span class="token punctuation">.</span>colors<span class="token punctuation">.</span>background<span class="token punctuation">,</span> <span class="token literal-property property">alignItems</span><span class="token operator">:</span> <span class="token string">'center'</span><span class="token punctuation">,</span> <span class="token literal-property property">paddingTop</span><span class="token operator">:</span> <span class="token number">10</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">card</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'90%'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> BackScreen<span class="token punctuation">;</span></code></pre></div><p>This screen is pretty much the same as other screens. The things you should note is that, first, the screen has uses the <code class="language-text">navigation</code> prop that is passed to components inside the navigation stack. Second, the screen has a button inside a card which, on press, will use the <code class="language-text">navigation</code> prop to go back using the <code class="language-text">goBack</code> method:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Button mode<span class="token operator">=</span><span class="token string">"contained"</span> onPress<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> navigation<span class="token punctuation">.</span><span class="token function">goBack</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span></code></pre></div><p>Now, go to the <code class="language-text">HomeScreen</code> and add a new card at the end of the ScrollView:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Card style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>card<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Title title<span class="token operator">=</span><span class="token string">"Navigate to 'Back' Screen"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Content<span class="token operator">></span> <span class="token operator"><</span>Button mode<span class="token operator">=</span><span class="token string">"contained"</span> onPress<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> navigation<span class="token punctuation">.</span><span class="token function">navigate</span><span class="token punctuation">(</span><span class="token string">'Back'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span> Navigate <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token punctuation">.</span>Content<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token operator">></span></code></pre></div><p>This card just shows a button to navigate to the route "Back". Let's add that route now.</p><p>In <code class="language-text">App.js</code> add a new <code class="language-text"><Stack.Screen></code> component below the previously added ones:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Back"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>BackScreen<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>It's ready now. Run the app if it isn't already running. You'll see a new card at the end of the list.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/IMG_1554.PNG" class="kg-image" alt="React Native Navigation Tutorial" loading="lazy" width="1170" height="2532" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/IMG_1554.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/IMG_1554.PNG 1000w, https://backend.shahednasser.com/content/images/2021/12/IMG_1554.PNG 1170w" sizes="(min-width: 720px) 720px"/></figure><p>Click on "Navigate" on the last card. You'll be navigated to the <code class="language-text">BackScreen</code>.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/IMG_1555.PNG" class="kg-image" alt="React Native Navigation Tutorial" loading="lazy" width="1170" height="2532" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/12/IMG_1555.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/12/IMG_1555.PNG 1000w, https://backend.shahednasser.com/content/images/2021/12/IMG_1555.PNG 1170w" sizes="(min-width: 720px) 720px"/></figure><p>Click on the "Go Back" button in the card. You'll be taken back to the <code class="language-text">HomeScreen</code>.</p><h2 id="conclusion">Conclusion</h2><p>In this tutorial, you learned how to use React Navigation to navigate between screens, pass a parameter from one screen to another, configure the header of a screen, add navigation event listeners, and go back programmatically to the previous screen.</p><p>Although this covers most use cases for using React Navigation, be sure to check out <a href="https://reactnavigation.org/docs/getting-started">their documentation</a> for more details on how to use it. </p>]]></content:encoded></item><item><title><![CDATA[4 Ways to Annoy Your Users and Push Them Away]]></title><description><![CDATA[Let me start by saying that, no, this article does not encourage you to annoy your users.]]></description><link>https://blog.shahednasser.com/4-ways-to-annoy-your-users-and-push-them-away/</link><guid isPermaLink="false">Ghost__Post__61af8e5b34d386060b4f22cd</guid><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 08 Dec 2021 12:56:53 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/aa8f258c5b9389ae5696dd7c22a9778f/hhh13-tEMU4lzAL0w-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/aa8f258c5b9389ae5696dd7c22a9778f/hhh13-tEMU4lzAL0w-unsplash-2.jpg" alt="4 Ways to Annoy Your Users and Push Them Away"/><p>Let me start by saying that, no, this article does not encourage you to annoy your users.</p><p>A lot of websites, whether on purpose or obliviously, seem to do everything they can to annoy their users. Blinded by all different methods to make money out of their website, promoting their products, or following methods that should, in theory, drive you more users, these websites end up annoying their users and making them not want to visit that site ever again.</p><p>In this article, I want you to take a step back and think if your website does any of the 4 things listed below that can annoy most, if not all users. If you do, then please take the necessary actions to undo these things to hopefully make your users like you a little more.</p><h2 id="overuse-of-pop-ups">Overuse of Pop-ups</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/5391322.jpg" class="kg-image" alt="4 Ways to Annoy Your Users and Push Them Away" loading="lazy" width="375" height="362"/></figure><p>I'll start this with a confession: I did this previously on my blog. When I first started my blog, I wanted more people to sign up for my newsletter. So, I adopted this technique from other websites. They obviously get a lot of sign-ups through this technique, so I should too, right?</p><p>Wrong. Not only did I barely get any subscribers compared to the subscribers I get now, with only a form at the end of an article, I also got so many complaints in the comments about the pop-up whenever I posted the article on social media.</p><p>And that was just for one pop-up. Imagine how your users think if you use a pop-up on every chance you get.</p><p>Now, I'm not saying you shouldn't use pop-ups on your website at all. You can and in a lot of cases should use pop-ups throughout your website, but the best way to use pop-ups is when they're triggered by a user's action.</p><p>For example, if the user clicks on the login button, it's more than ok to show them a pop-up for them to enter their credentials and log in. The overuse I talk about here is when you open a website, and pop-ups are shoved left and right in your face offering you discounts, newsletter subscriptions, or anything that basically benefits the website's owner. There's nothing wrong with benefiting from your website, we all need it. Just don't annoy the user while doing that.</p><h2 id="ads-exceeding-the-content">Ads Exceeding The Content</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/5391330.jpg" class="kg-image" alt="4 Ways to Annoy Your Users and Push Them Away" loading="lazy" width="375" height="285"/></figure><p>As mentioned earlier, we all want to benefit from our websites and there's nothing wrong with it. Ads are one way to do it. Websites that do a good job of showing ads either show them in empty areas where they don't affect the user's experience while exploring the content, or include ads in between the content, for example, in the middle of an article, but in a way that it's clear that it's an ad and it won't confuse the user while exploring the content.</p><p>On the other hand, we have websites that abuse every space in their webpage, including spaces that should be occupied with the content that the user is looking for, with ads. Some even go to the length of deceiving the user into thinking the ad is part of the content just so that they click on it.</p><p>Ads should not be an integral part of your website. By that, I mean that it should not be the main focus of the user when they visit your website. It should be part of the background or the user's ongoing experience, but not overlap with the content or replace it.</p><p>An approach that can also make your users tolerate your ads more is by using ad services that will show your users good quality ads. Take <a href="https://www.carbonads.net">Carbon</a> as an example. Carbon shows ads that are catered towards developers and designers. So, if that's your website's audience, then the ads (if placed correctly) will not be an issue for your users.</p><h2 id="shifting-layout">Shifting Layout</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/5391357.jpg" class="kg-image" alt="4 Ways to Annoy Your Users and Push Them Away" loading="lazy" width="375" height="187"/></figure><p>How annoying is it when a website seems to load, but then suddenly as you're about to click something, the layout of the website shifts and you end up clicking on something else?</p><p>Although this is never done on purpose (I think...unless you're a psycho), it can have a negative effect on your users. No one likes being misunderstood, and no one likes being forced to do something they didn't ask for. So, when a user is trying to simply perform an action, but that action is turned into something else because your content is finally loaded and the page's layout ends up changing, it can be very annoying.</p><p>This is so annoying that it's one of the 3 core <a href="https://web.dev/vitals/">web vital</a> metrics. <a href="https://web.dev/cls/">Cumulative Layout Shift</a> (CLS) measures the largest number of unexpected layout changes that can occur in the span of 5 seconds while the page is loading. This does not include layout changes as a response to a user's action, hence the use of "unexpected". </p><p>For example, a user clicking on the hide icon and an item is removed from the screen, causing a layout shift: that's ok. However, the layout keeps changing as the page is loading, and not in response to the user's action: that's bad.</p><p>This doesn't just annoy users. The core web vitals metrics are used across Google analytics and insights tools for your website, including <a href="https://search.google.com/search-console/about">Google's Search Console</a>. This means that a bad CLS score might affect how well your website does in search results, which will ultimately, affect your website's traffic.</p><p>If this happens on your website and you're unsure how you can resolve it, take a look at <a href="https://web.dev/cls/#how-to-improve-cls">tips to improve your CLS</a> score and try to apply them on your website.</p><h2 id="impossible-unsubscription">Impossible Unsubscription</h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/12/5391363.jpg" class="kg-image" alt="4 Ways to Annoy Your Users and Push Them Away" loading="lazy" width="375" height="220"/></figure><p>I'm not sure if it's just me, but it seems this one is becoming a thing among newsletters these days. It's becoming harder and harder to unsubscribe to newsletters these days.</p><p>For starters, some websites' newsletters go into a great deal of hiding their unsubscription link. They hide it among the <em>very</em> fine lines at the end of the email's footer, and you basically need a microscope to find it.</p><p>Other websites seem to have completely omitted to give the user the option to unsubscribe, or they just do a great job of hiding it that I simply cannot find it. Gmail now has an unsubscribe option now that lets you unsubscribe from any newsletter, but that doesn't work with every newsletter that you receive.</p><p>And then there are the websites that show you the subscribe button loud and clear, but when you click on it you're faced with many options, including checkboxes or reasons you want to unsubscribe, that can be confusing for the user. I recently tried to unsubscribe from a website and the unsubscription page showed me the checkboxes all checked with an unsubscribe button, but the text that they did a good job at not showing properly says "uncheck what you want to unsubscribe from". So, if a user doesn't take the time to read and just clicks the unsubscribe button, they will still be subscribed anyway.</p><p>We all don't want users to unsubscribe, that's obvious. However, that does not mean we should hold them hostage and fill their emails with our newsletters if that's not what they want. This gets especially annoying when websites consider you subscribed just by creating an account, then go to great lengths to make sure you don't unsubscribe.</p><p>If you don't want your users to unsubscribe, offer them quality content in your newsletter and make sure you don't spam them with emails. Then, if they still wish to unsubscribe, let them do it gracefully as you part ways. It's better than your newsletter being reported and ending up later on considered spam.</p><h2 id="conclusion">Conclusion</h2><p>Regardless of what the purpose behind your website is, your main goal should be to provide the best user experience. Once you do that, you're bound to get more traffic, more loyal users, and you'll be able to monetize your content, as well.</p><p>Instead of aiming at just "how can I sell this" or "how can I make money through this," instead of thinking from the mindset of a website owner, take a moment to think as a user, which at the end of the day we all are. "Why would I as a user buy this?" "Why would I as a user visit this website?" "What would make me as a user subscribe to this website's newsletter?" Once you change your mindset, your approach will change, and you'll annoy your users less.</p>]]></content:encoded></item><item><title><![CDATA[Programming Languages and Framework to Learn in 2022]]></title><description><![CDATA[In this article, I'll share some programming languages and frameworks you should consider learning in 2022.]]></description><link>https://blog.shahednasser.com/programming-languages-and-framework-to-learn-in-2022/</link><guid isPermaLink="false">Ghost__Post__61acc79934d386060b4f215e</guid><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 06 Dec 2021 12:09:31 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/63010ff3d9bc8e82d225abcfc241d36d/arif-riyanto-vJP-wZ6hGBg-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/63010ff3d9bc8e82d225abcfc241d36d/arif-riyanto-vJP-wZ6hGBg-unsplash-2.jpg" alt="Programming Languages and Framework to Learn in 2022"/><p>2022 is on its way, and as a new year start, we all have goals that we wish we can achieve. Whether you already are a programmer or you're looking to become one, there's a lot that you can learn to expand your knowledge or grow in your career.</p><p>In this article, I'll share some programming languages and frameworks you should consider learning in the upcoming year based on what's trending in the tech world. These are programming languages that can help you land a new job or just grow as a programmer.</p><p>Please note that although this article will include programming languages and frameworks that can be used for different apps and platforms, my main focus as always is web development. So, most of the languages and frameworks listed here are related to web development.</p><p>If you're interested in learning any of these programming languages, be sure to check out <a href="https://blog.shahednasser.com/best-platforms-to-learn-programming-in-2021">these websites that can help you learn and practice different programming languages</a>.</p><h2 id="programming-languages">Programming Languages</h2><h3 id="python">Python</h3><p>According to <a href="https://pypl.github.io/PYPL.html">PYPL</a>, <a href="https://www.python.org">Python</a> is the #1 popular language as of December 2021. Python is widely known for its ease of learning and use. If you're not familiar with Python, Python is a programming language that focuses on making the code human-readable. Using Python, you can create websites, apps, games, servers, and <a href="https://realpython.com/what-can-i-do-with-python/">more types of projects for different platforms</a>.</p><p>Python is one of the highly demanded skills among job postings. On Glassdoor, you can find <a href="https://www.glassdoor.co.uk/Job/python-jobs-SRCH_KO0,6.htm">over 14k jobs that require Python</a>. By learning Python, you have a higher chance of finding a job or upgrading your job.</p><h3 id="javascript">JavaScript</h3><p>JavaScript keeps rising in popularity over the years, as its possibilities keep expanding. It currently is the #3 popular language according to <a href="https://pypl.github.io/PYPL.html">PYPL</a>, and according to Statista, it's the <a href="https://www.statista.com/statistics/793628/worldwide-developer-survey-most-used-languages/">#1 programming language used by developers worldwide in 2021</a>. Started as just a frontend development language to add client-side functionalities to websites, it now can be used for many purposes. JavaScript can be used to create both the frontend and the backend of a website, making it a full-stack development language. JavaScript can also be used to create mobile apps, desktop software, CLI, and more.</p><p>JavaScript is another programming language that's popular in job postings. On Glassdoor, you can find <a href="https://www.glassdoor.co.uk/Job/javascript-jobs-SRCH_KO0,10.htm">over 11k job postings that require JavaScript</a>.</p><h3 id="java">Java</h3><p>Java is a programming language that has been popular for a very long time, and its popularity doesn't seem to be decreasing with time. Ranking #2 in popularity on <a href="https://pypl.github.io/PYPL.html">PYPL</a>, Java is a programming language that first appeared on May 26, 1995 (before I was even born). It's an object-oriented programming language that can be used to create servers, desktop software, android apps, and more.</p><p>As for job postings, Java is fairly popular as well among job postings. On Glassdoor, you can find <a href="https://www.glassdoor.co.uk/Job/javascript-jobs-SRCH_KO0,10.htm">over 8k job postings related to Java</a>.</p><h3 id="swift">Swift</h3><p>If you're interested in developing iOS apps, <a href="https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwiU_v6E9cz0AhVVh_0HHWkQD1QQFnoECAkQAQ&url=https%3A%2F%2Fdeveloper.apple.com%2Fswift%2F&usg=AOvVaw3pbWVRTZn3yQ4qZB4wpTdT">Swift</a> is what you need to learn. Ranking #8 on <a href="https://pypl.github.io/PYPL.html">PYPL</a>, Swift is a programming language created by Apple in 2014 and that can be used to create apps for iOS, iPadOS, macOS, tvOS, and watchOS. It's described as an intuitive and powerful language.</p><p>By learning Swift, you open your doors to becoming an iOS developer. Currently, there are <a href="https://www.glassdoor.co.uk/Job/ios-jobs-SRCH_KO0,3.htm">over 2k jobs for iOS developers</a> on Glassdoor.</p><h2 id="frameworkslibraries">Frameworks/Libraries</h2><h3 id="react">React</h3><p><a href="https://reactjs.org">React</a> is the <a href="https://www.statista.com/statistics/1124699/worldwide-developer-survey-most-used-frameworks-web/">most used web development framework worldwide in 2021</a> according to Statista. It's a JavaScript library that allows you to create fast and reactive websites easily. It's easy to learn and using React you have unlimited possibilities when creating websites.</p><p>React's popularity has been increasing among job postings. At the moment, it has <a href="https://www.glassdoor.co.uk/Job/react-jobs-SRCH_KE0,5.htm">over 5k job postings</a> on Glassdoor.</p><h3 id="flutter">Flutter</h3><p><a href="https://www.glassdoor.co.uk">Flutter</a> is a framework to create cross-platform apps. Using Flutter, you can create apps for mobile, desktop, and the web. It's a framework created by Google in 2017 and has been gaining a lot of popularity. According to Statista, it's now the <a href="https://www.statista.com/statistics/869224/worldwide-software-developer-working-hours/">most used cross-platform mobile framework in 2021</a>. </p><p>Flutter uses <a href="https://dart.dev">Dart</a> as a programming language, so you'll need to learn it as well. At the moment, Flutter has <a href="https://www.glassdoor.com/Job/flutter-developer-jobs-SRCH_KO0,17.htm">over 500 job postings</a> on Glassdoor.</p><h3 id="tailwind-css">Tailwind CSS</h3><p><a href="https://tailwindcss.com">Tailwind CSS</a> has gained so much popularity in the past few months. It's a CSS framework that aims to help create reusable components with minimal CSS code. Also, using its tree-shaking method when creating a production build of your code, the size of your CSS bundle will decrease based on what you are using in your website.</p><p>At the moment, you won't find a lot of jobs that require knowledge in Tailwind CSS. However, with the amount of popularity it's gaining and the framework's potential, I recommend learning Tailwind CSS as it's a big step up from other CSS frameworks.</p><h3 id="express">Express</h3><p>If you're looking into becoming a backend developer, Express is a good place to start. Express is a JavaScript library that helps you create a web server. By learning Express, you can become a backend or full-stack developer. Currently, there are <a href="https://www.glassdoor.co.uk/Job/full-stack-developer-jobs-SRCH_KO0,20.htm">almost 3k full-stack developer jobs</a> on Glassdoor.</p><h3 id="react-native">React Native</h3><p><a href="https://reactnative.dev">React Native</a> is another cross-platform mobile development framework. Based on React, React Native was developed to create cross-platform apps using React. According to Statista, it's <a href="https://www.statista.com/statistics/869224/worldwide-software-developer-working-hours/">the #2 most used cross-platform mobile framework among developers in 2021</a>. At the moment, React Native has <a href="https://www.glassdoor.co.uk/Job/react-native-jobs-SRCH_KO0,12.htm">over 5k job postings</a> on Glassdoor.</p><h3 id="laravel">Laravel</h3><p><a href="https://laravel.com">Laravel</a> is a <a href="https://www.php.net">PHP</a> framework that's used to create websites. Laravel follows the Model-View-Controller (MVC) architectural pattern. Although PHP's popularity keeps decreasing, Laravel is a great backend framework that keeps evolving with time. It now can be paired with popular frontend technologies like React, Vue, Tailwind CSS, and more, allowing you to have the best of both worlds stack. At the moment, there are <a href="https://www.glassdoor.co.uk/Job/laravel-jobs-SRCH_KE0,7.htm">over 600 job postings</a> on Glassdoor that require Laravel.</p><h3 id="vuejs">Vue.js</h3><p><a href="https://vuejs.org">Vue.js</a> is another popular JavaScript framework. According to Statista, it's the<a href="https://vuejs.org"> fifth most used web framework</a> in 2021. Vue.js is a front-end framework that's easy to learn and can be used to create a wide variety type of websites. It currently has <a href="https://www.glassdoor.co.uk/Job/vue-js-jobs-SRCH_KE0,6.htm">over 700 job postings</a> on Glassdoor.</p><h2 id="conclusion">Conclusion</h2><p>When choosing to learn a new programming language, you need to focus on the programming language that will help you grow as a developer. Focus on what goal you have as a developer, whether a new one or an experienced one, then see what programming languages and frameworks can help you achieve these goals.</p>]]></content:encoded></item><item><title><![CDATA[Implementing RBAC in Laravel Tutorial]]></title><description><![CDATA[In this tutorial, you'll learn how to implement RBAC in Laravel using Bouncer.]]></description><link>https://blog.shahednasser.com/implementing-rbac-in-laravel-tutorial/</link><guid isPermaLink="false">Ghost__Post__618135d1e78fe4060e2bf5ba</guid><category><![CDATA[Laravel]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 02 Dec 2021 15:07:47 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/e9d89904075105c7ca678ce999fa4506/sigmund-nv-ZYsvjIcE-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/e9d89904075105c7ca678ce999fa4506/sigmund-nv-ZYsvjIcE-unsplash-2.jpg" alt="Implementing RBAC in Laravel Tutorial"/><p>Role-Based Access Control, or RBAC, is the ability to add roles or restrict actions for users. It can be done in a general, high-level way, for example, to disallow some users from login into the admin panel. It can also be done more specifically, for example, allowing users to view a post but not edit it.</p><p>In this tutorial, you'll learn how to implement RBAC in Laravel using <a href="https://github.com/JosephSilber/bouncer">Bouncer</a>. Bouncer is a PHP package that lets you add roles and abilities to your Eloquent models.</p><p>You'll build an editor that lets the user create private posts with the ability to allow other users to view and edit their posts. You can find the code for this tutorial in <a href="https://github.com/shahednasser/laravel-rbac-tutorial">this GitHub repository</a>.</p><h2 id="prerequisites">Prerequisites</h2><p>You need to download <a href="https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwjH16_e3vnzAhWOQUEAHdipBuIQjBB6BAgQEAE&url=https%3A%2F%2Fgetcomposer.org%2Fdownload%2F&usg=AOvVaw0hifbxuQZySOtGjSzPWfJo">Composer</a> to follow along in this tutorial.</p><p>In addition, this tutorial uses Laravel 8 with PHP 7.3. To run Laravel 8, you need your PHP version to be at least 7.3.</p><p>You can check your PHP version in the terminal:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php -v</code></pre></div><p>NPM is also used in some parts of this tutorial, but it's not important for implementing RBAC. If you want to follow along with everything, make sure you have NPM installed. NPM is installed by installing <a href="https://nodejs.org">Node.js</a>.</p><h2 id="project-setup">Project Setup</h2><p>The first step is to set up the Laravel project. In your terminal, run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">composer</span> create-project laravel/laravel laravel-rbac-tutorial</code></pre></div><p>Once that is done, switch to the directory of the project:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> laravel-rbac-tutorial</code></pre></div><p>Then, you need to add your database configuration on <code class="language-text">.env</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=root DB_PASSWORD=</code></pre></div><p>Now migrate Laravel's default migrations to your database:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan migrate</code></pre></div><p>This will add Laravel's default tables as well as the <code class="language-text">users</code> table.</p><h2 id="implement-authentication">Implement Authentication</h2><p>To implement authentication easily, you can use <a href="https://github.com/laravel/ui">Laravel UI</a>. Install it with this command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">composer</span> require laravel/ui</code></pre></div><p>Then, run the following command to add the UI for authentication:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan ui bootstrap --auth</code></pre></div><p>This will add the directory <code class="language-text">app/Http/Controllers/Auth</code> with the controllers needed to implement authentication. It will also add the necessary view files <code class="language-text">resources/views</code> to add pages like login and register.</p><p>Then, compile the CSS and JavaScript assets added by the previous command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token operator">&&</span> <span class="token function">npm</span> run dev</code></pre></div><p>This command might end in an error. If so, run the <code class="language-text">dev</code> script again:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> run dev</code></pre></div><p>Finally, go to <code class="language-text">app/Providers/RouteServiceProvider.php</code> and change the value for the constant <code class="language-text">HOME</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">const</span> <span class="token constant">HOME</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'/'</span><span class="token punctuation">;</span></code></pre></div><p>Now, run the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan serve</code></pre></div><p>Then, go to <code class="language-text">localhost:8000</code>. You'll see the login form.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-3.24.13-PM.png" class="kg-image" alt="Implementing RBAC in Laravel Tutorial" loading="lazy" width="1554" height="640" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/11/Screen-Shot-2021-11-02-at-3.24.13-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/11/Screen-Shot-2021-11-02-at-3.24.13-PM.png 1000w, https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-3.24.13-PM.png 1554w" sizes="(min-width: 720px) 720px"/></figure><p>This is added by Laravel UI. Since you don't have a user yet, click on Register in the navigation bar. You'll see then a registration form.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-11.10.50-AM.png" class="kg-image" alt="Implementing RBAC in Laravel Tutorial" loading="lazy" width="1598" height="832" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/11/Screen-Shot-2021-11-02-at-11.10.50-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/11/Screen-Shot-2021-11-02-at-11.10.50-AM.png 1000w, https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-11.10.50-AM.png 1598w" sizes="(min-width: 720px) 720px"/></figure><p>After you register as a user, you'll be logged in.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-11.10.41-AM.png" class="kg-image" alt="Implementing RBAC in Laravel Tutorial" loading="lazy" width="1538" height="334" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/11/Screen-Shot-2021-11-02-at-11.10.41-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/11/Screen-Shot-2021-11-02-at-11.10.41-AM.png 1000w, https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-11.10.41-AM.png 1538w" sizes="(min-width: 720px) 720px"/></figure><h2 id="add-posts">Add Posts</h2><p>Now, you'll add posts that the user will be able to create.</p><p>Start by creating a migration:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan make:migration create_posts_table</code></pre></div><p>This will create a new migration file in <code class="language-text">database/migrations</code> with the file name's suffix <code class="language-text">create_posts_table</code>.</p><p>Open the migration file and replace its content with the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Database<span class="token punctuation">\</span>Migrations<span class="token punctuation">\</span>Migration</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Database<span class="token punctuation">\</span>Schema<span class="token punctuation">\</span>Blueprint</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Schema</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">CreatePostsTable</span> <span class="token keyword">extends</span> <span class="token class-name">Migration</span> <span class="token punctuation">{</span> <span class="token comment">/** * Run the migrations. * * @return void */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">up</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name static-context">Schema</span><span class="token operator">::</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'posts'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Blueprint</span> <span class="token variable">$table</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$table</span><span class="token operator">-></span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$table</span><span class="token operator">-></span><span class="token keyword type-declaration">string</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'title'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$table</span><span class="token operator">-></span><span class="token function">longText</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$table</span><span class="token operator">-></span><span class="token function">foreignId</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'user_id'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">constrained</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cascadeOnUpdate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cascadeOnDelete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$table</span><span class="token operator">-></span><span class="token function">timestamps</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/** * Reverse the migrations. * * @return void */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">down</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name static-context">Schema</span><span class="token operator">::</span><span class="token function">dropIfExists</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'posts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span></code></pre></div><p>Now, migrate the changes to create the <code class="language-text">posts</code> table:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan migrate</code></pre></div><p>Next, create the file <code class="language-text">app/Models/Post.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token comment">/** * Created by Reliese Model. */</span> <span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Models</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Carbon<span class="token punctuation">\</span>Carbon</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Database<span class="token punctuation">\</span>Eloquent<span class="token punctuation">\</span>Model</span><span class="token punctuation">;</span> <span class="token comment">/** * Class Post * * @property int $id * @property string $title * @property string $content * @property int $user_id * @property Carbon|null $created_at * @property Carbon|null $updated_at * * @property User $user * * @package App\Models */</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">Post</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">protected</span> <span class="token variable">$table</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'posts'</span><span class="token punctuation">;</span> <span class="token keyword">protected</span> <span class="token variable">$casts</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'user_id'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'int'</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">protected</span> <span class="token variable">$fillable</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'title'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'content'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'user_id'</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">belongsTo</span><span class="token punctuation">(</span><span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></span></code></pre></div><h2 id="add-post-form-page">Add Post Form Page</h2><p>You'll now add the page the user will use to create a new post or edit an old one.</p><p>In your terminal, run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan make:controller PostController</code></pre></div><p>This will create a new controller in <code class="language-text">app/Http/Controllers/PostController.php</code>. Open it and add a constructor method:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token comment">/** * Create a new controller instance. * * @return void */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'auth'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This adds the <code class="language-text">auth</code> middleware to all methods in this controller. This means that the user must be logged in before accessing any of the routes that point at this controller.</p><p>Next, add the <code class="language-text">postForm</code> function that renders the post form view:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">postForm</span> <span class="token punctuation">(</span><span class="token variable">$id</span> <span class="token operator">=</span> <span class="token constant">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/** @var User $user */</span> <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$post</span> <span class="token operator">=</span> <span class="token constant">null</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/** @var Post $post */</span> <span class="token variable">$post</span> <span class="token operator">=</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">find</span><span class="token punctuation">(</span><span class="token variable">$id</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$post</span> <span class="token operator">||</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">!==</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">redirectTo</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post-form'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'post'</span> <span class="token operator">=></span> <span class="token variable">$post</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Notice that this receives an optional <code class="language-text">id</code> paramter, then retrieves the post based on that ID. It also validates that the post exists and belongs to the current logged-in user. This is because this method will handle the request for both creating a post and editing a post.</p><p>Then, create the view <code class="language-text">resources/views/post-form.blade.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php">@<span class="token keyword">extends</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'layouts.app'</span><span class="token punctuation">)</span> @<span class="token function">push</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'head_scripts'</span><span class="token punctuation">)</span> <span class="token operator"><</span>link rel<span class="token operator">=</span><span class="token string double-quoted-string">"stylesheet"</span> href<span class="token operator">=</span><span class="token string double-quoted-string">"https://cdn.jsdelivr.net/npm/trix@1.3.1/dist/trix.css"</span><span class="token operator">></span> @endpush @<span class="token function">section</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"container"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"row justify-content-center"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"col-md-8"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-header"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span> <span class="token operator">?</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Edit Post'</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token class-name return-type">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'New Post'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-body"</span><span class="token operator">></span> <span class="token operator"><</span>form method<span class="token operator">=</span><span class="token string double-quoted-string">"POST"</span> action<span class="token operator">=</span><span class="token string double-quoted-string">"#"</span><span class="token operator">></span> @csrf @<span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post'</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"alert alert-danger"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$message</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @enderror <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-group"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"title"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Title'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"text"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"title"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"title"</span> placeholder<span class="token operator">=</span><span class="token string double-quoted-string">"Title"</span> required value<span class="token operator">=</span><span class="token string double-quoted-string">"{{ <span class="token interpolation"><span class="token variable">$post</span></span> ? <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">title</span></span> : old('title') }}"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control @error('title') is-invalid @enderror"</span> <span class="token operator">/</span><span class="token operator">></span> @<span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'title'</span><span class="token punctuation">)</span> <span class="token operator"><</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"invalid-feedback"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$message</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> @enderror <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-group"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"content"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Content'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> @<span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">)</span> <span class="token operator"><</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"invalid-feedback"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$message</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> @enderror <span class="token operator"><</span>input id<span class="token operator">=</span><span class="token string double-quoted-string">"content"</span> type<span class="token operator">=</span><span class="token string double-quoted-string">"hidden"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"content"</span> value<span class="token operator">=</span><span class="token string double-quoted-string">"{{ <span class="token interpolation"><span class="token variable">$post</span></span> ? <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">content</span></span> : old('content') }}"</span><span class="token operator">></span> <span class="token operator"><</span>trix<span class="token operator">-</span>editor input<span class="token operator">=</span><span class="token string double-quoted-string">"content"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>trix<span class="token operator">-</span>editor<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-group"</span><span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string double-quoted-string">"submit"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"btn btn-primary"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Submit'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>script src<span class="token operator">=</span><span class="token string double-quoted-string">"https://cdn.jsdelivr.net/npm/trix@1.3.1/dist/trix.js"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span> @endsection</code></pre></div><p>This shows a form with 2 inputs. A title text input, and a text editor for the content. The text editor is <a href="https://github.com/basecamp/trix">Trix</a>, an easy-to-use open-source editor.</p><p>You still need to add the link to the page. So, in <code class="language-text">resources/views/layouts/app.blade.php</code> add the following menu item in the <code class="language-text">ul</code> under the comment <code class="language-text"><!-- Left Side Of Navbar --></code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>li <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"nav-item"</span><span class="token operator">></span> <span class="token operator"><</span>a <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"nav-link"</span> href<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('post.form') }}"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'New Post'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span></code></pre></div><p>Finally, add the route to the page in <code class="language-text">routes/web.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post/{id?}'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">PostController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'postForm'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post.form'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>If you go to the website now, you'll notice a new link in the navbar that says "New Post". If you click on it, you'll see the form you created for the posts.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-12.22.29-PM.png" class="kg-image" alt="Implementing RBAC in Laravel Tutorial" loading="lazy" width="1544" height="832" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/11/Screen-Shot-2021-11-02-at-12.22.29-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/11/Screen-Shot-2021-11-02-at-12.22.29-PM.png 1000w, https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-12.22.29-PM.png 1544w" sizes="(min-width: 720px) 720px"/></figure><h2 id="save-posts">Save Posts</h2><p>Before you implement the save functionality for posts, it's time to use Bouncer to implement RBAC.</p><p>In your terminal, run the following to install Bouncer:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">composer</span> require silber/bouncer v1.0.0-rc.10</code></pre></div><p>Then, in <code class="language-text">app/Models/User.php</code> make the following changes:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">use</span> <span class="token package">Silber<span class="token punctuation">\</span>Bouncer<span class="token punctuation">\</span>Database<span class="token punctuation">\</span>HasRolesAndAbilities</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Authenticatable</span> <span class="token punctuation">{</span> <span class="token keyword">use</span> <span class="token package">HasApiTokens</span><span class="token punctuation">,</span> HasFactory<span class="token punctuation">,</span> Notifiable<span class="token punctuation">,</span> HasRolesAndAbilities<span class="token punctuation">;</span></code></pre></div><p>Next, run the following command to add the migrations that Bouncer needs:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan vendor:publish --tag<span class="token operator">=</span><span class="token string">"bouncer.migrations"</span></code></pre></div><p>Finally, migrate these changes:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan migrate</code></pre></div><p>Bouncer is now ready to use. You can now add the save post functionality.</p><p>In <code class="language-text">app/Http/Controllers/PostController.php</code> add the new <code class="language-text">savePost</code> method:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">savePost</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token variable">$id</span> <span class="token operator">=</span> <span class="token constant">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/** @var $user */</span> <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name static-context">Validator</span><span class="token operator">::</span><span class="token function">validate</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'title'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'required|min:1'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'content'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'required|min:1'</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//all valid, validate id if not null</span> <span class="token comment">/** @var Post $post */</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$post</span> <span class="token operator">=</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">find</span><span class="token punctuation">(</span><span class="token variable">$id</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">back</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">withErrors</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'post'</span> <span class="token operator">=></span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Post does not exist'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token variable">$post</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Post</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//set data</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">title</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'title'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">content</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">associate</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name static-context">Bouncer</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">toManage</span><span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">redirectToRoute</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post.form'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'id'</span> <span class="token operator">=></span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>In this method, you first validate that both <code class="language-text">title</code> and <code class="language-text">content</code> were entered in the form. Then, if the optional parameter <code class="language-text">id</code> is passed to the method you validate if it exists and if it belongs to this user. This is similar to the <code class="language-text">postForm</code> method.</p><p>After validating everything, you set <code class="language-text">title</code> and <code class="language-text">content</code>. Then, if the post is new you set the current user as the owner of the post with <code class="language-text">$post->user()->associate($user);</code>.</p><p>The important bit is here:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name static-context">Bouncer</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">toManage</span><span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Using the <code class="language-text">Bouncer</code> facade, you can use functions like <code class="language-text">allow</code>, which takes a user model. Then, you can give different types of permissions to the user. By using <code class="language-text">toManage</code>, you give the user all sorts of management permissions over the <code class="language-text">$post</code> instance.</p><p>Now, add the route for this method in <code class="language-text">routes/web.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post/{id?}'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">PostController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'savePost'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post.save'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Finally, change the form action in <code class="language-text">resources/views/post-form.blade.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>form method<span class="token operator">=</span><span class="token string double-quoted-string">"POST"</span> action<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('post.save', ['id' => <span class="token interpolation"><span class="token variable">$post</span></span> ? <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">id</span></span> : null]) }}"</span><span class="token operator">></span></code></pre></div><p>If you go now the New Post page and try adding a post by filling the <code class="language-text">title</code> and <code class="language-text">content</code> fields then clicking Submit, you'll be redirected back to the form with the content filled in which means the post has been added.</p><h2 id="show-posts">Show Posts</h2><p>To make the posts added visible to the user, change the <code class="language-text">index</code> method in <code class="language-text">app/Http/Controller/HomeController.php</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token comment">/** * Show the application dashboard. * * @return \Illuminate\Contracts\Support\Renderable */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">index</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/** @var User $user */</span> <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//get all posts</span> <span class="token variable">$posts</span> <span class="token operator">=</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">where</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'user_id'</span><span class="token punctuation">,</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'posts'</span> <span class="token operator">=></span> <span class="token variable">$posts</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will retrieve the posts that are made by the currently logged-in user.</p><p>Next, change <code class="language-text">resources/views/home.blade.php</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php">@<span class="token keyword">extends</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'layouts.app'</span><span class="token punctuation">)</span> @<span class="token function">section</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"container"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"row justify-content-center"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"col-md-8"</span><span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'My Posts'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> @<span class="token function">forelse</span> <span class="token punctuation">(</span><span class="token variable">$posts</span> <span class="token keyword">as</span> <span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-header"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">title</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-body"</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token operator">!</span><span class="token operator">!</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">content</span> <span class="token operator">!</span><span class="token operator">!</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-footer"</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'By '</span> <span class="token operator">.</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token property">name</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">-</span> <span class="token operator"><</span>a href<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('post.form', ['id' => <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">id</span></span>]) }}"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Edit'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @<span class="token keyword">empty</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-body"</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'You have no posts'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @endforelse <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @endsection</code></pre></div><p>This will show the list of posts that the user has added if there are any.</p><p>If you open the home page now, you should see the post you added earlier.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-1.11.16-PM.png" class="kg-image" alt="Implementing RBAC in Laravel Tutorial" loading="lazy" width="1568" height="574" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/11/Screen-Shot-2021-11-02-at-1.11.16-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/11/Screen-Shot-2021-11-02-at-1.11.16-PM.png 1000w, https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-1.11.16-PM.png 1568w" sizes="(min-width: 720px) 720px"/></figure><h2 id="add-view-and-edit-access">Add View and Edit Access</h2><p>In this section, you will be adding the functionality to allow access to other users either to edit or view a post. This will show how RBAC implementation works and how you can restrict or give access to a certain model for users.</p><p>In <code class="language-text">resources/views/home.blade.php</code> change the element with class <code class="language-text">.card-footer</code> that holds the Edit link to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-footer"</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'By '</span> <span class="token operator">.</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token property">name</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">-</span> <span class="token operator"><</span>a href<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('post.form', ['id' => <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">id</span></span>]) }}"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Edit'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> <span class="token operator">-</span> <span class="token operator"><</span>a href<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('post.access', ['id' => <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">id</span></span>, 'type' => 'view']) }}"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Change view access...'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> <span class="token operator">-</span> <span class="token operator"><</span>a href<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('post.access', ['id' => <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">id</span></span>, 'type' => 'edit']) }}"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Change edit access...'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></code></pre></div><p>This adds 2 links for a new page which is access form. This page allows the user to change view or edit access for other users to the post.</p><p>In <code class="language-text">app/Http/Controllers/PostController.php</code> add a new method <code class="language-text">accessForm</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">accessForm</span> <span class="token punctuation">(</span><span class="token variable">$id</span><span class="token punctuation">,</span> <span class="token variable">$type</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/** @var App/Models/User $user */</span> <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/** @var Post $post */</span> <span class="token variable">$post</span> <span class="token operator">=</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">find</span><span class="token punctuation">(</span><span class="token variable">$id</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$post</span> <span class="token operator">||</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">!==</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">redirectTo</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//get all users</span> <span class="token variable">$users</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">where</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'id'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'!='</span><span class="token punctuation">,</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post-access'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'post'</span> <span class="token operator">=></span> <span class="token variable">$post</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'users'</span> <span class="token operator">=></span> <span class="token variable">$users</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'type'</span> <span class="token operator">=></span> <span class="token variable">$type</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This route receives 2 parameters: <code class="language-text">id</code> which is the post ID, and <code class="language-text">type</code> which is the type of access. The type of access can be view or edit.</p><p>In this method you first validate the post and make sure it exists and it belongs to the current logged in user. Then, you retrieve all other users and send them to the view <code class="language-text">post-access</code> which we'll create now.</p><p>Create <code class="language-text">resources/views/post-access.blade.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php">@<span class="token keyword">extends</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'layouts.app'</span><span class="token punctuation">)</span> @<span class="token function">section</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"container"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"row justify-content-center"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"col-md-8"</span><span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string double-quoted-string">"Change "</span> <span class="token operator">.</span> <span class="token function">ucwords</span><span class="token punctuation">(</span><span class="token variable">$type</span><span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string double-quoted-string">" Access to Post"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-body"</span><span class="token operator">></span> <span class="token operator"><</span>form method<span class="token operator">=</span><span class="token string double-quoted-string">"POST"</span> action<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post.access.save'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'id'</span> <span class="token operator">=></span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'type'</span> <span class="token operator">=></span> <span class="token variable">$type</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> @csrf @<span class="token function">forelse</span> <span class="token punctuation">(</span><span class="token variable">$users</span> <span class="token keyword">as</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-group"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"user_{{ <span class="token interpolation"><span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span></span> }}"</span><span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"checkbox"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"users[]"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"user_{{ <span class="token interpolation"><span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span></span> }}"</span> value<span class="token operator">=</span><span class="token string double-quoted-string">"{{ <span class="token interpolation"><span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span></span> }}"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control d-inline mr-3"</span> @<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token variable">$type</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> checked @<span class="token keyword">endif</span> style<span class="token operator">=</span><span class="token string double-quoted-string">"width: fit-content; vertical-align: middle;"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>span<span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">name</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @<span class="token keyword">empty</span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'There are no users'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> @endforelse <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-group"</span><span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string double-quoted-string">"submit"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"btn btn-primary"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Save'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @endsection</code></pre></div><p>This shows the list of users with checkboxes. Those who already have access will already by checked, others unchecked.</p><p>Now, you'll create the route that handles saving the access for the post. In <code class="language-text">app/Http/Controllers/PostController.php</code> add the new method <code class="language-text">saveAccess</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">saveAccess</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token variable">$id</span><span class="token punctuation">,</span> <span class="token variable">$type</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/** @var User $user */</span> <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/** @var Post $post */</span> <span class="token variable">$post</span> <span class="token operator">=</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">find</span><span class="token punctuation">(</span><span class="token variable">$id</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$post</span> <span class="token operator">||</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">!==</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">redirectTo</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token variable">$users</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'users'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$disallowedUserNotIn</span> <span class="token operator">=</span> <span class="token variable">$users</span><span class="token punctuation">;</span> <span class="token variable">$disallowedUserNotIn</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">;</span> <span class="token comment">//disallow users not checked</span> <span class="token variable">$disallowedUsers</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">whereNotIn</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'id'</span><span class="token punctuation">,</span> <span class="token variable">$disallowedUserNotIn</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/** @var User $disallowedUser */</span> <span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$disallowedUsers</span> <span class="token keyword">as</span> <span class="token variable">$disallowedUser</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$disallowedUser</span><span class="token operator">-></span><span class="token function">disallow</span><span class="token punctuation">(</span><span class="token variable">$type</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//allow checked users</span> <span class="token variable">$allowedUsers</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">whereIn</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'id'</span><span class="token punctuation">,</span> <span class="token variable">$users</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/** @var User $allowedUser */</span> <span class="token keyword">foreach</span><span class="token punctuation">(</span><span class="token variable">$allowedUsers</span> <span class="token keyword">as</span> <span class="token variable">$allowedUser</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$allowedUser</span><span class="token operator">-></span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token variable">$type</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token function">back</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This route also receives 2 parameters <code class="language-text">id</code> and <code class="language-text">type</code>, same as <code class="language-text">accessForm</code>. You also validate the post by checking that it exists and that it belongs to the current user.</p><p>Then, you retrieve the checked users from the <code class="language-text">request</code>. There are 2 actions to do here: disallow unchecked users to perform the action <code class="language-text">type</code> on the post, and allow checked users to perform the action <code class="language-text">type</code> on the post.</p><p>So, you first retrieve the users that are not in the array <code class="language-text">$users</code> which holds the checked user IDs. Then, you loop over them to perform the following method on each of them:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token variable">$disallowedUser</span><span class="token operator">-></span><span class="token function">disallow</span><span class="token punctuation">(</span><span class="token variable">$type</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>When the trait <code class="language-text">HasRolesAndAbilities</code> is added to a model, which we did earlier to the model <code class="language-text">User</code>, a set of methods are added to that m0del. One of them is <code class="language-text">disallow</code> which disallows the user a certain ability and you can specify a model to be more specific about what that ability is disabled on.</p><p>So, here you are disallowing the user in the loop to perform the action <code class="language-text">$type</code> on the post <code class="language-text">$post</code>.</p><p>Next, you retrieve the users that are in the <code class="language-text">$users</code> array and that should be granted the ability to perform action <code class="language-text">$type</code> on them. You loop over them and perform the following method:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token variable">$allowedUser</span><span class="token operator">-></span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token variable">$type</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Similar to <code class="language-text">disallow</code>, <code class="language-text">allow</code> is another method that is added by the trait <code class="language-text">HasRolesAndAbilities</code>. It allows the user to have the ability <code class="language-text">$type</code> either in general or on a given model that is specified as a second parameter.</p><p>Here, you allow the user to perform the action <code class="language-text">$type</code> on the post <code class="language-text">$post</code>.</p><p>Now, add the new routes in <code class="language-text">routes/web.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post/access/{id}/{type}'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">PostController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'accessForm'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post.access'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post/access/{id}/{type}'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">PostController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'saveAccess'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post.access.save'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Now, there are some changes left to do. First, you need to change the condition in <code class="language-text">postForm</code> which allows users who have the permission to edit or view the post to access the page:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$post</span> <span class="token operator">||</span> <span class="token punctuation">(</span><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">!==</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">&&</span> <span class="token operator">!</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token operator">!</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'view'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">redirectTo</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>You also need to allow users who have edit permission to edit the post in <code class="language-text">savePost</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$post</span> <span class="token operator">||</span> <span class="token punctuation">(</span><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">!==</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">&&</span> <span class="token operator">!</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">back</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">withErrors</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'post'</span> <span class="token operator">=></span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Post does not exist'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>In <code class="language-text">app/Http/Controllers/HomeController.php</code> in the <code class="language-text">index</code> method change the method to also retrieve the posts that the user has edit or view permissions on:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token comment">/** * Show the application dashboard. * * @return \Illuminate\Contracts\Support\Renderable */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">index</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/** @var User $user */</span> <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//get all posts</span> <span class="token variable">$posts</span> <span class="token operator">=</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">where</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'user_id'</span><span class="token punctuation">,</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//get posts that the user is allowed to view or edit</span> <span class="token variable">$postIds</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token variable">$abilities</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">getAbilities</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/** @var \Silber\Bouncer\Database\Ability */</span> <span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$abilities</span> <span class="token keyword">as</span> <span class="token variable">$ability</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$postIds</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token variable">$ability</span><span class="token operator">-></span><span class="token property">entity_id</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token variable">$posts</span> <span class="token operator">=</span> <span class="token variable">$posts</span><span class="token operator">-></span><span class="token function">orWhereIn</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'id'</span><span class="token punctuation">,</span> <span class="token variable">$postIds</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'posts'</span> <span class="token operator">=></span> <span class="token variable">$posts</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This is done using the <code class="language-text">getAbilities</code> method that is added on the <code class="language-text">User</code> model like <code class="language-text">allow</code> and <code class="language-text">disallow</code>. Each ability holds the id of the model it represents under <code class="language-text">entity_id</code>. We use that to get the ID of posts that the user has view or edit permissions on and retrieve them to show them on the home page.</p><p>In <code class="language-text">resources/views/home.blade.php</code> change the element with class <code class="language-text">.card-footer</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-footer"</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'By '</span> <span class="token operator">.</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token property">name</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">-</span> <span class="token operator"><</span>a href<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('post.form', ['id' => <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">id</span></span>]) }}"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'View'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> @<span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'manage'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator"><</span>a href<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('post.access', ['id' => <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">id</span></span>, 'type' => 'view']) }}"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Change view access...'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> <span class="token operator">-</span> <span class="token operator"><</span>a href<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('post.access', ['id' => <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">id</span></span>, 'type' => 'edit']) }}"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Change edit access...'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> @endcan <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></code></pre></div><p>You now only show the change access links to the user that manages the post so that not everyone that has access to the post can make changes to its access settings. This can be done by using the <code class="language-text">@can</code> blade directive which accepts the ability name and optionally a model instance. In this case, we check if the current user can <code class="language-text">manage</code> the post <code class="language-text">$post</code>.</p><p>Finally, you need to make changes to <code class="language-text">resources/views/post-form.blade.php</code> to ensure that if the user has view permission only they can't make edits on the post. This means that the form will become read-only.</p><p>Change the content of the element with the class <code class="language-text">card</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-header"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span> <span class="token operator">?</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'View Post'</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token class-name return-type">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'New Post'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"card-body"</span><span class="token operator">></span> <span class="token operator"><</span>form method<span class="token operator">=</span><span class="token string double-quoted-string">"POST"</span> action<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('post.save', ['id' => <span class="token interpolation"><span class="token variable">$post</span></span> ? <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">id</span></span> : null]) }}"</span><span class="token operator">></span> @csrf @<span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post'</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"alert alert-danger"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$message</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @enderror @<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$post</span> <span class="token operator">&&</span> <span class="token operator">!</span><span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"alert alert-info"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'You have view permissions only'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @<span class="token keyword">endif</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-group"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"title"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Title'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"text"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"title"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"title"</span> placeholder<span class="token operator">=</span><span class="token string double-quoted-string">"Title"</span> required value<span class="token operator">=</span><span class="token string double-quoted-string">"{{ <span class="token interpolation"><span class="token variable">$post</span></span> ? <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">title</span></span> : old('title') }}"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control @error('title') is-invalid @enderror"</span> @<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token variable">$post</span> <span class="token operator">&&</span> <span class="token operator">!</span><span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> disabled<span class="token operator">=</span><span class="token string double-quoted-string">"true"</span> @<span class="token keyword">endif</span> <span class="token operator">/</span><span class="token operator">></span> @<span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'title'</span><span class="token punctuation">)</span> <span class="token operator"><</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"invalid-feedback"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$message</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> @enderror <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-group"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"content"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Content'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> @<span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">)</span> <span class="token operator"><</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"invalid-feedback"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$message</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> @enderror @<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token variable">$post</span> <span class="token operator">&&</span> <span class="token operator">!</span><span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token operator">!</span><span class="token operator">!</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">content</span> <span class="token operator">!</span><span class="token operator">!</span><span class="token punctuation">}</span> @<span class="token keyword">else</span> <span class="token operator"><</span>input id<span class="token operator">=</span><span class="token string double-quoted-string">"content"</span> type<span class="token operator">=</span><span class="token string double-quoted-string">"hidden"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"content"</span> value<span class="token operator">=</span><span class="token string double-quoted-string">"{{ <span class="token interpolation"><span class="token variable">$post</span></span> ? <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">content</span></span> : old('content') }}"</span><span class="token operator">></span> <span class="token operator"><</span>trix<span class="token operator">-</span>editor input<span class="token operator">=</span><span class="token string double-quoted-string">"content"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>trix<span class="token operator">-</span>editor<span class="token operator">></span> @<span class="token keyword">endif</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$post</span> <span class="token operator">||</span> <span class="token class-name">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-group"</span><span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string double-quoted-string">"submit"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"btn btn-primary"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Submit'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @<span class="token keyword">endif</span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></code></pre></div><p>This makes the <code class="language-text">title</code> input disabled, shows the content of the post readable rather than in an editor, and hides the submit button when the user does not have <code class="language-text">edit</code> permissions.</p><p>Let's test all of this together. You first need to create another user to test this out so go ahead and register as a new user. Then log in again with the user you previously created and click on "Change view access..." on one of the posts you created. You'll see a form with the user you created and a checkbox.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-1.49.30-PM.png" class="kg-image" alt="Implementing RBAC in Laravel Tutorial" loading="lazy" width="1562" height="494" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/11/Screen-Shot-2021-11-02-at-1.49.30-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/11/Screen-Shot-2021-11-02-at-1.49.30-PM.png 1000w, https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-1.49.30-PM.png 1562w" sizes="(min-width: 720px) 720px"/></figure><p>Check the checkbox and click save. This will give the new user the ability to view the post. </p><p>Now, log out and log in again with the new user. You'll see the post in the home page.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-2.37.38-PM.png" class="kg-image" alt="Implementing RBAC in Laravel Tutorial" loading="lazy" width="1670" height="572" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/11/Screen-Shot-2021-11-02-at-2.37.38-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/11/Screen-Shot-2021-11-02-at-2.37.38-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/11/Screen-Shot-2021-11-02-at-2.37.38-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-2.37.38-PM.png 1670w" sizes="(min-width: 720px) 720px"/></figure><p>Click on View. You'll see the same form that you saw before when creating a post but the title input is disabled and the editor is not available anymore.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-2.40.46-PM.png" class="kg-image" alt="Implementing RBAC in Laravel Tutorial" loading="lazy" width="1600" height="722" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/11/Screen-Shot-2021-11-02-at-2.40.46-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/11/Screen-Shot-2021-11-02-at-2.40.46-PM.png 1000w, https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-2.40.46-PM.png 1600w" sizes="(min-width: 720px) 720px"/></figure><p>Let's try giving the user edit permissions now. Log out and login with the first user again. This time, click on "Change edit access" on the post. Give the new user access and click Save.</p><p>Again, logout and login as the new user. Then, click on View on the post in the home page. You should now be able to edit the post.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-2.41.35-PM.png" class="kg-image" alt="Implementing RBAC in Laravel Tutorial" loading="lazy" width="1568" height="836" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/11/Screen-Shot-2021-11-02-at-2.41.35-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/11/Screen-Shot-2021-11-02-at-2.41.35-PM.png 1000w, https://backend.shahednasser.com/content/images/2021/11/Screen-Shot-2021-11-02-at-2.41.35-PM.png 1568w" sizes="(min-width: 720px) 720px"/></figure><p>You can even try going back to the first user and removing the edit access for the new user on the post. They will no longer be able to edit the post.</p><h2 id="conclusion">Conclusion</h2><p>RBAC adds abilities and roles to users which allows you to manage permissions in your app. In this tutorial, you learned how to use Bouncer to implement RBAC in Laravel, allowing or disallowing permissions and abilities for users.</p><p>Be sure to check out <a href="https://github.com/JosephSilber/bouncer">Bouncer's documentation</a> to learn more about what you can do with the package.</p>]]></content:encoded></item><item><title><![CDATA[Invideo Review: Make creative video with online video editor]]></title><description><![CDATA[Free online video editing tool that has got everything from the right interface to perfect pricing to help users make professional-quality videos]]></description><link>https://blog.shahednasser.com/invideo-review-make-creative-video-with-online-video-editor/</link><guid isPermaLink="false">Ghost__Post__61a4e66053259e060be11801</guid><category><![CDATA[Reviews]]></category><dc:creator><![CDATA[Sanket Shah]]></dc:creator><pubDate>Mon, 29 Nov 2021 15:05:15 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/ec66388a8b16bc9f0d2826eb5cbb8afa/ryan-clark-eeVzGZ_d49k-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/ec66388a8b16bc9f0d2826eb5cbb8afa/ryan-clark-eeVzGZ_d49k-unsplash-2.jpg" alt="Invideo Review: Make creative video with online video editor"/><p>In this era of digital <a href="https://blog.shahednasser.com/tag/tips/">technology</a>, it is absolutely possible to make top-quality videos online without downloading or installing any software program or application. If you have a Windows or a Mac computer, you can easily use video editing tools like InVideo for creating professional-looking videos without spending a dime.</p><p>This free online video editing tool has got everything starting from the right interface and supported video sizes and formats to perfect pricing to help users make professional-quality videos within just five minutes.</p><p><strong>What’s InVideo?</strong></p><p>Put simply, <a href="https://invideo.io/">InVideo</a> is a free, online, cloud-based video-making and editing tool that is being used on a very wide scale by businesses these days. One of the best things about this tool is it helps users in making professional-grade visuals using free and premium images, music, templates, and visuals in almost any web browser.</p><p>Templates available with InVideo can help in creating superior quality visual content. The tool is specifically useful for beginners in video editing. With this tool, you get a large number of beautiful templates for making different varieties of videos. You can use this tool for making:</p><ul><li>Intro/outro videos</li><li>Promotional and product videos</li><li>Greetings and motion quotes</li><li>Tutorials</li><li>Video presentations</li><li>Webinars</li><li>Social media videos</li><li>YouTube video testimonials</li><li>Promos</li></ul><p>The best thing about using this tool is you can use the same templates for creating videos in different formats and sizes for different social media channels such as Instagram, YouTube, and Facebook.</p><p><strong>Use Readymade Templates for Making Creative Videos</strong></p><p>InVideo is one of the best online video-making tools for publishers, bloggers, marketers, individuals, YouTubers, and companies. Businesses and marketers can use it most effectively for creating professional-grade visual content for enhancing traffic on their sites.</p><p>Now, when it comes to using InVideo, there are three varied ways of using it to your best advantage.</p><ul><li><strong>Premade Templates: </strong>You can use the premade templates available with this tool for making and editing visual matter without taking a lot of time.</li><li><strong>Text-to-Video: </strong>This option is highly useful when it comes to transforming textual matter into visual content with complete ease. The text here shows according to the line in the video content.</li><li><strong>Blank Template: </strong>InVideo also features blank templates that can be used for experienced video editing professionals. The marketers can use blank templates for starting their video-making assignment from scratch.</li></ul><p><strong>Engaging Videos Are Easy to Make with InVideo</strong></p><p>The free-to-use video-making tool that InVideo is, allows users to not just create and share slideshow-format visuals, short videos, and home videos within minutes, but even comes with a media stock library to make your videos more engaging.</p><p>Yes, you can use the images, visuals, and sound effects available with InVideo’s media stock library to make your videos even more wonderful and attention-grabbing. The library of images, videos, and audio will help you make awesome content based on varied themes and occasions.</p><p>The stunning attributes of this tool make it one of the best in the market. And it is only because of its excellent features that InVideo has been successful in satiating the requirements of over 120000 consumers. The tool also boasts of a customer satisfaction rate of 98%, which speaks of the efficiency and usefulness of the tool.</p><p>With InVideo, you get the flexibility of editing video clips, soundtracks, images, text, and captions easily and using the same for making superior quality visuals that grab attention within seconds.</p><p>Not to mention, the videos made using this tool can easily be personalized for narrating stories that serve business and personal outcomes. You get the option of making your choice from different images, videos, stickers, and text boxes for making professional-grade videos within a time span of 5 minutes.</p><p><strong>Express Your Creativity to the Fullest</strong></p><p>With InVideo, you can make professional documentaries and even <a href="https://blog.shahednasser.com/how-to-easily-add-share-links-for-each-social-media-platform/">social media</a> content of the highest quality. As a user, you get the flexibility of creating videos from scratch. The pre-existing templates available with InVideo will make your video-making job convenient.</p><p>From Halloween and birthday themes to different video formats like slideshows, memes, presentations, promotional videos - everything is there. The users of this tool will never fall behind in enticing their prospects or clients simply because of the splendid features of the tool and also because of its ease of use.</p><p>There’s no other platform as suitable as InVideo for creating videos for professional and personal branding and even for special occasions such as birthdays and anniversaries.</p><p>This is one versatile video-making tool that helps users in making crisp and simple, slideshow-style videos with the perfect amalgamation of music, images, and text. You can even use it for creating complicated yet powerful videos with twisted storylines.</p><p>The beginners in video making and editing can use this tool to hone their skills and polish the same to make better videos. As a user, you can make your presence felt on varied social media channels simply by posting top-quality visual content consistently.</p><p>You can rule Facebook or YouTube, and Instagram with videos that grab attention and gain you and your brand huge recognition. There’s InVideo to do it all for you and that too without paying a single dime for anything that the tool does. Of course, going for the premium version will surely cost you a certain amount.</p><p><strong>The Bottom Line</strong></p><p>InVideo has gained huge popularity among the masses and specifically among video editing enthusiasts for the remarkable features it comes loaded with. It helps you create some of the most stunning visuals to be posted on different social media platforms.</p><p>If you are on the lookout for that perfect tool to help you make <a href="https://blog.hubspot.com/marketing/best-product-videos-list">business videos for product promotion</a>, InVideo is one you should go for. The easy-to-use features of this tool will not get you into any complex situation while making your product videos.</p><p>If possible, go through the instructional videos and tutorials available online regarding the use of InVideo and gain good hands-on using the tool. So, without wasting any more time, start using InVideo now!</p>]]></content:encoded></item><item><title><![CDATA[Internet of Things Application Development: 8 Inspiring Projects]]></title><description><![CDATA[In this article, we’ll look at the most exciting projects to come out of the IoT application development services industry in recent years.]]></description><link>https://blog.shahednasser.com/internet-of-things-application-development-8-inspiring-projects/</link><guid isPermaLink="false">Ghost__Post__619f5eb353259e060be117d7</guid><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Kateryna Sukhotepla]]></dc:creator><pubDate>Thu, 25 Nov 2021 10:06:35 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/1e17a9896a8b8df6e7b62e6f40239a23/dan-lefebvre-RFAHj4tI37Y-unsplash-2-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/1e17a9896a8b8df6e7b62e6f40239a23/dan-lefebvre-RFAHj4tI37Y-unsplash-2-2.jpg" alt="Internet of Things Application Development: 8 Inspiring Projects"/><p>Internet of Things (IoT) Application Development is one of the most exciting fields in the ICT industry today. If you own or want to start an IoT software development company, you are on the right track. IoT devices will surpass 25.4 billion in 2030, and it seems like every industry, from agriculture to retail, will need to hire an Internet of Things development company at some stage. </p><p>In this article, we’ll look at the most exciting projects to come out of the <a href="https://anywhere.epam.com/business/services/iot-development">IoT application development services</a> industry in recent years.</p><h2 id="the-most-exciting-internet-of-things-application-development-projects-so-far">The Most Exciting Internet of Things Application Development Projects (So Far)</h2><h3 id="manufacturing-projects">Manufacturing Projects </h3><p>Industrial and manufacturing companies were the frontrunners of IoT. Companies use IoT apps and devices to monitor the production floor, use augmented reality to track equipment and navigate large warehouses and automate quality and stock controls. It can speed up systems through automation and cut costs.</p><p><strong>Example 1</strong>: Howden in Scotland devices to overlay real-time data from connected products with 3D augmented reality to show clients how to solve problems with equipment, step by step. This ended up reducing downtime and associated costs.</p><h3 id="transportation">Transportation</h3><p>Tesla started off the connected car trend in 2012, introducing over-the-air software capabilities for the first time. Since then, almost all car manufacturers are integrating IoT technology into their designs.</p><p><strong>Example 2</strong>: KWRL in the US runs a large school bus fleet. They’ve started using Samsara, a wireless fleet tracking platform to coordinate bus routes and keep running on schedule. The app allows them to have real visibility into where their buses are at any given moment and provides instant engine fault alerts for added safety.</p><p><strong>Example 3</strong>: Omnibus in Finland uses Telia’s connected vehicle solution to optimize the use of their equipment and to reduce fuel consumption by constantly collecting and analyzing data.</p><p><strong>Example 4:</strong> Caledonian Logistics in Scotland uses an app called MyGeotab to track driver behavior and raise alerts if abnormal activity is detected. This reduces stock losses due to fraud or reckless behavior.</p><h3 id="energy">Energy</h3><p>IoT devices can reduce energy consumption dramatically. While we are already aware of applications like smart lighting that controls lights and air conditioning in smart buildings, energy savings can be realized on a much larger scale. </p><p><strong>Example 5:</strong> Enel in Italy used a custom IoT development company to improve grid reliability by using AI to analyze real-time sensor data, smart meter data, and weather data.</p><h3 id="retail">Retail</h3><p>Retails may use in-store digital signage, customer tracking, and engagement in stores but also use the Internet of Things application development services behind the scenes for goods monitoring and inventory management. </p><p><strong>Example 6: </strong>Walmart uses 7 million IoT data points to control food safety, including remotely managing HVAC and refrigeration across their mega-stores. They also use smart lighting to keep energy consumption optimal. </p><p><strong>Example 7</strong>: nuMedia in the US uses mixed-reality technology called PRSONAS that mimics human experiences to enhance customer experiences through smart digital kiosks with interactive self-service holograms. These holograms act as virtual sales reps and product specialists.</p><h3 id="smart-cities">Smart Cities</h3><p>We are already familiar with smart homes, but the concept is being expanded on to include larger cities and towns. </p><p><strong>Example 8</strong>: Amsterdam has already deployed hundreds of smart LED streetlights with cameras and public Wi-Fi in Hoekenrodeplein. The lights are remotely controlled but will automatically adapt to different lighting conditions. The Vincent van Gogh museum uses an app and Bluetooth sensors to provide information about exhibits and increase visitor engagement.</p><h2 id="conclusion">Conclusion</h2><p>These projects are exciting but only the tip of the iceberg. Internet of Things application development is going to change the technological and business landscape dramatically in the next few years. Make sure that you are part of the revolution by getting into the game early.</p>]]></content:encoded></item><item><title><![CDATA[How to Build a Social Media App]]></title><description><![CDATA[In this article, we'll talk about different tips on how to build a social media app and what features you should include.]]></description><link>https://blog.shahednasser.com/how-to-build-a-social-media-app/</link><guid isPermaLink="false">Ghost__Post__619f558953259e060be117bb</guid><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Chatty Garrate]]></dc:creator><pubDate>Thu, 25 Nov 2021 09:30:23 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/09b2aca78a9f4fc64966047cbcab6324/sara-kurfess-6lcT2kRPvnI-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/09b2aca78a9f4fc64966047cbcab6324/sara-kurfess-6lcT2kRPvnI-unsplash-2.jpg" alt="How to Build a Social Media App"/><p>Social media apps are great for business or simply as a way of keeping in touch with friends and family. As a result, many developers are now seeking to build their own social media apps. While there are numerous ways to create your own social media platform, it's important to know the basics before you start building. In this article, we'll talk about different tips on how to build a social media app and what features you should include.</p><h2 id="determine-what-kind-of-app-you-want-to-create">Determine What Kind of App You Want to Create</h2><p>Before you begin designing your app, you first need to decide what kind of app you want to create. This will help you determine the features that you can implement into your app. For example, if you're interested in creating a platform for sharing photos, then you may want to consider creating an app where professional and amateur photographers can share their work.</p><p>In addition, learning about the other social media apps that are already out there can help you gauge what the market needs. It's going to be difficult to compete against big players like Facebook and Twitter if you don't have any unique features. So, by researching popular social media sites and <a href="https://carlstromproductions.com/virtual-event-production-content-ideas-strategy/">knowing your target audience</a>, you can learn more about what people are using and what they would like to see added to their existing platforms.</p><h2 id="decide-how-your-app-will-work">Decide How Your App Will Work</h2><p>After deciding what type of app you'd like to create, you need to think about how it will work. This means deciding on what kind of features are essential in making your social media app successful. Basic features such as a newsfeed, search bar, photo uploads, and profile pages are all very important when developing a social media app. However, depending on your app idea, you might also want to add features like chat rooms, video streaming, location-based services, and group messaging.</p><p>No matter what kind of features you choose to include, make sure that each feature is easy to use. If users struggle to find something within your app, they won't stick around long enough to really enjoy the experience. Also, ensure that you provide clear instructions so that new users can get up and running quickly.</p><h2 id="choose-a-platform">Choose a Platform</h2><p>Once you've decided on what features you want to include, it's time to pick which platform you plan to develop your app on. There are plenty of options available, including iOS, Android, Windows Phone 7, and more. Each platform has its own set of advantages and disadvantages, but ultimately it comes down to personal preference.</p><p>For example, <a href="https://andela.com/ios-architects/">iOs developers</a> will need to consider Apple's strict guidelines regarding third-party applications. On the other hand, android developers will need to take into account Google's restrictions concerning advertising. Regardless of what platform you choose to use, make sure that it supports the features you intend to include. Otherwise, you risk having to scrap your entire project.</p><h2 id="test-different-features-and-prototypes">Test Different Features and Prototypes</h2><p>When you have chosen a platform and determined what features you want to support, it's time to test them! Testing allows you to identify whether your selected features actually work as expected. Don't be discouraged if you discover that your prototype isn't working correctly on the first try. Instead, keep testing until you come across issues that you weren't aware of before. Once you do this, you'll be able to fix these problems quickly and efficiently.</p><p>In addition, you should always be testing different features with different versions of your app. This helps you determine whether certain features aren't compatible with older devices or operating systems. For example, if you're planning to release an iPhone version of your app, you should test it on both the original device and the new model. Doing this will allow you to catch any compatibility errors early on and prevent them from becoming major issues later on.</p><h2 id="market-your-app">Market Your App</h2><p>Once you're ready to launch your social media app, you must decide how to market it. There are many ways to promote your app, ranging from traditional marketing methods to newer online techniques. This includes sharing information about your app via websites and blogs and sending out press releases. The goal here is to help people learn more about your app, increase awareness, and encourage them to download it.</p><p>However, don't expect instant success. It takes time for your app to gain traction. In fact, some apps only receive a small amount of traffic after their initial release. As a result, it may take months to see significant results. Don't give up though; once you start seeing positive reviews and feedback, you'll eventually reach the tipping point where your app becomes popular.</p><h2 id="the-bottom-line">The Bottom Line</h2><p>Creating a successful social media app takes a lot of hard work. There are many factors that you need to carefully consider before launching it. However, by following the steps outlined above, you can create an engaging social media application that stands apart from all others. And who knows, maybe one day your <a href="https://blog.shahednasser.com/how-to-easily-add-share-links-for-each-social-media-platform">social media platform</a> will become the most popular in the world!</p>]]></content:encoded></item><item><title><![CDATA[React Context Tutorial For Beginners]]></title><description><![CDATA[In this tutorial, you'll learn the basics of Contexts and how you can use them in your projects.]]></description><link>https://blog.shahednasser.com/react-context-tutorial-for-beginners/</link><guid isPermaLink="false">Ghost__Post__617bfd6f7ec5e905d9bde7dd</guid><category><![CDATA[React]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 10 Nov 2021 14:43:44 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/9ddfe0134aa1295aa6df113abfe30c23/ferenc-almasi-tvHtIGbbjMo-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/9ddfe0134aa1295aa6df113abfe30c23/ferenc-almasi-tvHtIGbbjMo-unsplash-2.jpg" alt="React Context Tutorial For Beginners"/><p><a href="https://reactjs.org/docs/context.html">Context</a> in React is one of the features that a lot of beginners stay away from because they find it complicated. The concept makes it sound like it's something advanced, however, when you learn it you'll realize that not only it's simple, but it will make your development simpler.</p><p>In this tutorial, you'll learn the basics of Contexts and how you can use them in your projects. We'll create a context to access the logged-in user in multiple components and pages.</p><p>You can find the code for this tutorial on <a href="https://github.com/shahednasser/react-context-tutorial">this GitHub repository</a>.</p><h2 id="project-setup">Project Setup</h2><p>In your terminal, use the following command to create a new React app:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-react-app react-context-tutorial</code></pre></div><p>Once the installation is done, go to the <code class="language-text">react-context-tutorial</code> directory:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> react-context-tutorial</code></pre></div><p>Then, install the following dependencies which you'll use throughout the tutorial:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i axios react-bootstrap bootstrap@5.1.3 react-cookie react-router-dom</code></pre></div><p>Here's what each dependency is for:</p><ol><li><a href="https://github.com/axios/axios">axios</a>: to send POST request to log in the user.</li><li><a href="https://react-bootstrap.github.io/getting-started/introduction">bootstrap and react-bootstrap</a>: for easy styling</li><li><a href="https://www.npmjs.com/package/react-cookie">react-cookie</a>: to store the user token in the cookies</li><li><a href="https://reactrouter.com">react-router-dom</a>: to add pages and routing between them.</li></ol><h2 id="create-the-context">Create the Context</h2><p>You need to create the context next to be able to use it in your components. To create a context you can use <code class="language-text">React.createContext</code> passing it the default value for that context.</p><p>In most cases, in the context's value you should have the object or variable you want to share between components and a setter function to change its value.</p><p>In the <code class="language-text">src</code> directory, create the file <code class="language-text">UserContext.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">const</span> UserContext <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">createContext</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">user</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token function-variable function">setUser</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> UserContext<span class="token punctuation">;</span></code></pre></div><p>This will create a context having as a default value an object that has the property <code class="language-text">user</code>, which by default is <code class="language-text">null</code>, and a property <code class="language-text">setUser</code>, which by default is a function that does nothing. You also need to export the context to use it in components.</p><h2 id="using-the-context-provider">Using the Context Provider</h2><p>The next step to use a context is by using the Context Provider. The Provider is a component that you should use at the highest level you want the context to be used in, and the children of that component will then have access to the context value.</p><p>In most cases, you'll add the Provider component at the very highest level of your app and all components will be children of that provider.</p><p>In this tutorial, you will put the provider in the <code class="language-text">App</code> component which will render all the routes in the App.</p><p>Change the content of <code class="language-text">src/App.js</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token string">'bootstrap/dist/css/bootstrap.min.css'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>user<span class="token punctuation">,</span> setUser<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>UserContext<span class="token punctuation">.</span>Provider value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> user<span class="token punctuation">,</span> setUser <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>UserContext<span class="token punctuation">.</span>Provider<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span></code></pre></div><p>First, you import the stylesheet for Bootstrap. This is for styling reasons only.</p><p>Then, inside the <code class="language-text">App</code> component, you first define a <code class="language-text">user</code> state variable and set its initial value to null.</p><p>In the returned JSX, you use the <code class="language-text">UserContext.Provider</code> component. This is the context provider of <code class="language-text">UserContext</code>. Every context created with <code class="language-text">React.createContext</code> has this provider.</p><p>The provider takes a prop <code class="language-text">value</code>, which is the value of the context. You pass it the <code class="language-text">user</code> state variable created earlier and the <code class="language-text">setUser</code> function to change the <code class="language-text">user</code> state variable. This means that when other components use <code class="language-text">setUser</code> function, the <code class="language-text">user</code> state variable will change to the new value everywhere it's used.</p><h2 id="add-navigation-component">Add Navigation Component</h2><p>You'll now add the <code class="language-text">Navigation</code> component. This <code class="language-text">Navigation</code> component will show the <em>Log In </em>link when <code class="language-text">user</code> is <code class="language-text">null</code>, and will show the <em>Log Out</em> link when the <code class="language-text">user</code> is not <code class="language-text">null</code>.</p><p>Create the file <code class="language-text">src/components/Navigation.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useContext <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Container<span class="token punctuation">,</span> Nav<span class="token punctuation">,</span> Navbar <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Link <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-router-dom"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> UserContext <span class="token keyword">from</span> <span class="token string">"../UserContext"</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Navigation</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span>user<span class="token punctuation">,</span> setUser<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useContext</span><span class="token punctuation">(</span>UserContext<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">logout</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setUser</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Navbar bg<span class="token operator">=</span><span class="token string">"light"</span> expand<span class="token operator">=</span><span class="token string">"lg"</span><span class="token operator">></span> <span class="token operator"><</span>Container<span class="token operator">></span> <span class="token operator"><</span>Navbar<span class="token punctuation">.</span>Brand href<span class="token operator">=</span><span class="token string">"/"</span><span class="token operator">></span>React Context<span class="token operator"><</span><span class="token operator">/</span>Navbar<span class="token punctuation">.</span>Brand<span class="token operator">></span> <span class="token operator"><</span>Navbar<span class="token punctuation">.</span>Toggle aria<span class="token operator">-</span>controls<span class="token operator">=</span><span class="token string">"basic-navbar-nav"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Navbar<span class="token punctuation">.</span>Collapse id<span class="token operator">=</span><span class="token string">"basic-navbar-nav"</span><span class="token operator">></span> <span class="token operator"><</span>Nav className<span class="token operator">=</span><span class="token string">"me-auto"</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token operator">!</span>user <span class="token operator">&&</span> <span class="token operator"><</span>Link to<span class="token operator">=</span><span class="token string">"/login"</span><span class="token operator">></span>Log In<span class="token operator"><</span><span class="token operator">/</span>Link<span class="token operator">></span><span class="token punctuation">}</span> <span class="token punctuation">{</span>user <span class="token operator">&&</span> <span class="token operator"><</span>Nav<span class="token punctuation">.</span>Link href<span class="token operator">=</span><span class="token string">"#"</span> onClick<span class="token operator">=</span><span class="token punctuation">{</span>logout<span class="token punctuation">}</span><span class="token operator">></span>Log Out<span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token punctuation">.</span>Link<span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Navbar<span class="token punctuation">.</span>Collapse<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Navbar<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Notice the usage of <code class="language-text">useContext</code>. This is a React hook that lets you retrieve the value of a Context inside consumers, which are children of a context provider. So, all child elements of <code class="language-text">UserContext.Providers</code>, including all of their children elements recursively, can use <code class="language-text">useContext</code> to get the value of the context.</p><p>Here, you use <code class="language-text">useContext</code> passing it the <code class="language-text">UserContext</code> context to retrieve the <code class="language-text">user</code> variable and <code class="language-text">setUser</code> function. Then, based on the value of <code class="language-text">user</code> you either show or hide the login and log-out links.</p><p>Notice the <code class="language-text">logout</code> function, which is a handler of the <code class="language-text">onClick</code> event of the log-out link. This function uses <code class="language-text">setUser</code> to change the value of <code class="language-text">user</code> to <code class="language-text">null</code>, which will change the value everywhere it's being used or consumed.</p><h2 id="add-home-page">Add Home Page</h2><p>Next, you'll create the Home component which will show on the Home page. This component does nothing special. It just shows the <code class="language-text">Navigation</code> component and shows the user a message based on whether they're logged in or not.</p><p>Create <code class="language-text">src/pages/Home.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useContext <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Container <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Navigation <span class="token keyword">from</span> <span class="token string">"../components/Navigation"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> UserContext <span class="token keyword">from</span> <span class="token string">"../UserContext"</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Home</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span>user<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useContext</span><span class="token punctuation">(</span>UserContext<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token operator"><</span>Navigation <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Container<span class="token operator">></span> <span class="token punctuation">{</span><span class="token operator">!</span>user <span class="token operator">&&</span> <span class="token operator"><</span>h1<span class="token operator">></span>You're not logged <span class="token keyword">in</span><span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span><span class="token punctuation">}</span> <span class="token punctuation">{</span>user <span class="token operator">&&</span> <span class="token operator"><</span>h1<span class="token operator">></span>You're logged <span class="token keyword">in</span> <span class="token keyword">with</span> <span class="token punctuation">{</span>user<span class="token punctuation">.</span>token<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Here you also use the <code class="language-text">useContext</code> hook to retrieve the <code class="language-text">user</code>. Notice that you are only retrieving the <code class="language-text">user</code> and not <code class="language-text">setUser</code> because you won't need it here.</p><p>If the <code class="language-text">user</code> is <code class="language-text">null</code>, the message "You're not logged in" will show, else the message "You're logged in with {user.token}" will show. The value of <code class="language-text">user</code> here will change when any consumer of the context uses <code class="language-text">setUser</code> to change the value.</p><h2 id="add-home-route"> Add Home Route</h2><p>After you've created the <code class="language-text">Home</code> component, it's time to show it.</p><p>In <code class="language-text">src/App.js</code> add the import for the <code class="language-text">Home</code> component as well as the imports needed for routing from <code class="language-text">react-router-dom</code> at the top of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> BrowserRouter <span class="token keyword">as</span> Router<span class="token punctuation">,</span> Switch<span class="token punctuation">,</span> Route <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-router-dom"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Home <span class="token keyword">from</span> <span class="token string">'./pages/Home'</span><span class="token punctuation">;</span></code></pre></div><p>Then, change the returned JSX to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>UserContext<span class="token punctuation">.</span>Provider value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> user<span class="token punctuation">,</span> setUser <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Router<span class="token operator">></span> <span class="token operator"><</span>Switch<span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>Home<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Switch<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Router<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>UserContext<span class="token punctuation">.</span>Provider<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Now, the <code class="language-text">Home</code> component is a child of <code class="language-text">UserContext.Provider</code> and subsequently it can access the context with its children using <code class="language-text">useContext</code>.</p><p>If you run the server now:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>You'll see a home page showing you that you're not logged in.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-29-at-8.46.04-PM.png" class="kg-image" alt="React Context Tutorial For Beginners" loading="lazy" width="964" height="394" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-29-at-8.46.04-PM.png 600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-29-at-8.46.04-PM.png 964w" sizes="(min-width: 720px) 720px"/></figure><h2 id="add-login-page">Add Login Page</h2><p>Now, you'll add the login page which will allow the users to log in. To simulate the login process, you'll use <a href="https://reqres.in">Reqres</a>, a fake REST API that lets you simulate a lot of requests including the user login request.</p><p>In the login page, you first need to check if the user is already logged in. If they are, you'll redirect to the home page.</p><p>If the user is not logged in then you'll show a form with email and password fields. When the user clicks the submit button, you send a request to Reqres' login API endpoint. Then, if the request is successful you set the logged-in user in the context.</p><p>Create the file <code class="language-text">src/pages/LogIn.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> axios <span class="token keyword">from</span> <span class="token string">"axios"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useContext<span class="token punctuation">,</span> useEffect<span class="token punctuation">,</span> useRef<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Form<span class="token punctuation">,</span> Button <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useHistory <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-router"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Navigation <span class="token keyword">from</span> <span class="token string">"../components/Navigation"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> UserContext <span class="token keyword">from</span> <span class="token string">"../UserContext"</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">LogIn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>email<span class="token punctuation">,</span> setEmail<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">"george.bluth@reqres.in"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>password<span class="token punctuation">,</span> setPassword<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">{</span>user<span class="token punctuation">,</span> setUser<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useContext</span><span class="token punctuation">(</span>UserContext<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> history <span class="token operator">=</span> <span class="token function">useHistory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> buttonRef <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//check if user is logged in or not</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>user <span class="token operator">!==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//redirect home</span> history<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>history<span class="token punctuation">,</span> user<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> buttonRef<span class="token punctuation">.</span>current<span class="token punctuation">.</span>disabled <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token comment">//login user</span> axios<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">'https://reqres.in/api/login'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>email<span class="token punctuation">,</span> password<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>data<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//set token in local storage</span> <span class="token function">setUser</span><span class="token punctuation">(</span><span class="token punctuation">{</span> email<span class="token punctuation">,</span> password<span class="token punctuation">,</span> <span class="token literal-property property">token</span><span class="token operator">:</span> data<span class="token punctuation">.</span>token <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'An error occurred, please try again later.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> buttonRef<span class="token punctuation">.</span>current<span class="token punctuation">.</span>disabled <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token operator"><</span>Navigation <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span> className<span class="token operator">=</span><span class="token string">"w-75 mx-auto"</span><span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span>Log In<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span> controlId<span class="token operator">=</span><span class="token string">"formBasicEmail"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Email address<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"email"</span> placeholder<span class="token operator">=</span><span class="token string">"Enter email"</span> required value<span class="token operator">=</span><span class="token punctuation">{</span>email<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setEmail</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Group className<span class="token operator">=</span><span class="token string">"mb-3"</span> controlId<span class="token operator">=</span><span class="token string">"formBasicPassword"</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Password<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"password"</span> placeholder<span class="token operator">=</span><span class="token string">"Password"</span> required value<span class="token operator">=</span><span class="token punctuation">{</span>password<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setPassword</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Group<span class="token operator">></span> <span class="token operator"><</span>Button variant<span class="token operator">=</span><span class="token string">"primary"</span> type<span class="token operator">=</span><span class="token string">"submit"</span> ref<span class="token operator">=</span><span class="token punctuation">{</span>buttonRef<span class="token punctuation">}</span><span class="token operator">></span> Submit <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>Just as explained above, you have the <code class="language-text">email</code> and <code class="language-text">password</code> state variables to make the form inputs <a href="https://reactjs.org/docs/forms.html#controlled-components">controlled components</a>. Notice that the initial value of <code class="language-text">email</code> is one of the emails for users available in Reqres. </p><p>You retrieve <code class="language-text">user</code> and <code class="language-text">setUser</code> from the context using <code class="language-text">useContext</code>. You also use <code class="language-text">useHistory</code> which is a <a href="https://reactrouter.com/web/api/Hooks/usehistory">React Router hook</a> to get access to the <code class="language-text">history</code> instance which you'll use to navigate.</p><p>In <code class="language-text">useEffect</code>, which will run whenever the <code class="language-text">user</code> or <code class="language-text">history</code> variables change, you check if the user is logged in by checking if the value is null or not. If it's not null, it means the user is logged in so you navigate to the homepage using <code class="language-text">history</code>.</p><p>Inside <code class="language-text">handleSubmit</code>, which is the event listener for the form submit event, you send a POST request to Reqres' fake API endpoint to login. This endpoint returns a fake token to be used. If the request succeeds, you use <code class="language-text">setUser</code> to set the user. Otherwise, you show an error.</p><p>The last thing left is to add the <code class="language-text">LogIn</code> page as a route in <code class="language-text">src/App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>UserContext<span class="token punctuation">.</span>Provider value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> user<span class="token punctuation">,</span> setUser <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Router<span class="token operator">></span> <span class="token operator"><</span>Switch<span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/login"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>LogIn<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>Home<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Switch<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Router<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>UserContext<span class="token punctuation">.</span>Provider<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Now, run the server if it's not already running. Then, open the Log In page by clicking on the link in the navigation bar. You'll see a form with a prefilled email address.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-29-at-11.04.57-PM.png" class="kg-image" alt="React Context Tutorial For Beginners" loading="lazy" width="2000" height="645" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-29-at-11.04.57-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-29-at-11.04.57-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-29-at-11.04.57-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-29-at-11.04.57-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>You can enter any password you want then click <em>Submit</em>. Once the request is performed and the token is retrieved, you'll be redirected to the home page and the message for the logged in user will show.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-29-at-11.07.58-PM.png" class="kg-image" alt="React Context Tutorial For Beginners" loading="lazy" width="1696" height="396" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-29-at-11.07.58-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-29-at-11.07.58-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-29-at-11.07.58-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-29-at-11.07.58-PM.png 1696w" sizes="(min-width: 720px) 720px"/></figure><p>Notice that the link in the navigation bar changed to show "Log Out" instead of "Log In". This is because the <code class="language-text">user</code> variable passed through the context is updated everywhere it's being consumed. If you click on Log Out, the <code class="language-text">user</code> variable will be <code class="language-text">null</code> again.</p><h2 id="use-cookies">Use Cookies</h2><p>When you log in a user you want to store their token in a cookie so that the next time they visit the website they're still logged in. In this section, you'll store the token in a cookie and set the initial value of the <code class="language-text">user</code> state variable based on it.</p><p>In <code class="language-text">src/App.js</code> add the following import at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useCookies <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-cookie'</span><span class="token punctuation">;</span></code></pre></div><p>Then, change the definition of the <code class="language-text">user</code> state to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>cookies<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useCookies</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>user<span class="token punctuation">,</span> setUser<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span>cookies<span class="token punctuation">.</span>token <span class="token operator">?</span> <span class="token punctuation">{</span><span class="token literal-property property">token</span><span class="token operator">:</span> cookies<span class="token punctuation">.</span>token<span class="token punctuation">}</span> <span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>The library <code class="language-text">react-cookie</code> exposes the <code class="language-text">useCookies</code> hook. Using this hook, you can retrieve the <code class="language-text">cookies</code> object of cookies, where the properties are the name of each cookie.</p><p>If the cookie <code class="language-text">token</code> is found, you set the initial value of <code class="language-text">user</code> to the object <code class="language-text">{token: cookies.token}</code>, else set it to <code class="language-text">null</code>.</p><p>The next step is to set the cookie on login. In <code class="language-text">src/pages/LogIn.js</code> add the import at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useCookies <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-cookie"</span><span class="token punctuation">;</span></code></pre></div><p>Then, change <code class="language-text">setUser</code> in the fulfilment callback for the login request to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">setCookie</span><span class="token punctuation">(</span><span class="token string">'token'</span><span class="token punctuation">,</span> data<span class="token punctuation">.</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setUser</span><span class="token punctuation">(</span><span class="token punctuation">{</span> email<span class="token punctuation">,</span> password<span class="token punctuation">,</span> <span class="token literal-property property">token</span><span class="token operator">:</span> data<span class="token punctuation">.</span>token <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>The last step is to remove the cookie on log out. In <code class="language-text">src/components/Navigation.js</code> add the import at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useCookies <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-cookie"</span><span class="token punctuation">;</span></code></pre></div><p>Then, inside <code class="language-text">logout</code> function add the following line:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">removeCookie</span><span class="token punctuation">(</span><span class="token string">'token'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>If you test the website now, you can log in, close the tab then visit the website again and you'll still be logged in.</p><h2 id="conclusion">Conclusion</h2><p>In this tutorial, you learned how to use Context in React. It makes it so much easier to re-use data that you'll frequently use in different components without having to pass the variable and its setter through multiple components. </p>]]></content:encoded></item><item><title><![CDATA[Get started with Medusa Part 2: Make the Server Your Own]]></title><description><![CDATA[In this tutorial, you will start making changes to the server to make it your own.]]></description><link>https://dev.to/medusajs/get-started-with-medusa-part-2-make-the-server-your-own-gka</link><guid isPermaLink="false">Ghost__Post__6189441453259e060be115db</guid><category><![CDATA[Reviews]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[eCommerce]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 08 Nov 2021 15:46:13 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/6b016085b23247acd751ff03ce39861f/part-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/6b016085b23247acd751ff03ce39861f/part-1.png" alt="Get started with Medusa Part 2: Make the Server Your Own"/><p>In the first part of this tutorial series, I compared <a href="https://github.com/medusajs/medusa">Medusa</a> and Shopify to showcase how Medusa <a href="https://blog.shahednasser.com/get-started-with-medusa-the-open-source-alternative-to-shopify/">is the open-source alternative to Shopify</a>. Where Shopify lacks when it comes to its pricing plans, minimal customization abilities, and inability to fit for every business use case, Medusa can compensate for it.</p><p>Medusa is an open-source headless commerce solution that allows you to own your stack and make it fit into whatever use case your business needs. It is fast and very flexible.</p><p>In the previous tutorial, you learned about Medusa’s 3 components and how you can install and run each of them. It is a very easy process that can get your store up and running in seconds.</p><p>In this tutorial, you will start making changes to the server to make it your own. You will learn how to create new API endpoints, services, and subscribers. The API you will create will retrieve the products with the most sales, and you will create a service and subscriber to help us do that.</p><p>The code for this tutorial is on <a href="https://github.com/shahednasser/medusa-store-tutorial">this GitHub repository</a>.</p><h2 id="prerequisites">Prerequisites</h2><p>This tutorial assumes you have already read and followed along with <a href="https://dev.to/medusajs/get-started-with-medusa-the-open-source-alternative-to-shopify-305j">part 1</a>. In the first part, you learn how to setup the Medusa store, which you will make changes to in this tutorial, as well as the Medusa storefront and the admin. If you have not went through it yet, please do before continuing with this tutorial.</p><p>In addition, you need to have Redis installed and running on your machine to be able to use subscribers. So, if you do not have it installed and you want to follow along with the tutorial you should go ahead and <a href="http://redis.io/">install it</a>.</p><h2 id="add-a-service">Add a Service</h2><p>As mentioned earlier, you will be creating an API endpoint that allows you to get the top products, i.e. the products with the most sales.</p><p>In Medusa, services generally handle the logic of models or entities in one place. They hold helper functions that allow you to retrieve or perform action on these models. Once you put them in a service, you can access the service from anywhere in your Medusa project.</p><p>So, in this tutorial, you will create a service <code class="language-text">TopProductsService</code> that will hold all the logic needed to update products with their number of sales and to retrieve the products sorted by their number of sales.</p><p>To create a service, start by creating the file <code class="language-text">src/services/top-products.js</code>with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import { BaseService } from "Medusa-interfaces"; class TopProductsService extends BaseService { constructor({ productService, orderService }) { super(); this.productService_ = productService; this.orderService_ = orderService; } } </code></pre></div><p>Here are a few things to note about this service:</p><ol><li>When this service is retrieved in other places in your code, the service should be referred to as the camel-case version of the file name followed by “Service”. In this case, the file name is <code class="language-text">top-product</code>, so to access it in other places we use <code class="language-text">topProductsService</code>.</li><li>Similarly to how you will use this service, we inject as dependencies the <code class="language-text">productService</code> and <code class="language-text">orderService</code> in the constructor. When you create classes in Medusa, you can use dependency injection to get access to services.</li></ol><p><strong>Implement getTopProducts</strong></p><p>The next step is to add the method <code class="language-text">getTopProducts</code> to the <code class="language-text">TopProductsService</code> class. This method will retrieve the products from the database, sort them by their number of sales, then return the top 5 products.</p><p>Inside <code class="language-text">TopProductsService</code> class add the new method:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">async getTopProducts() { const products = await this.productService_.list({ status: ['published'] }, { relations: ["variants", "variants.prices", "options", "options.values", "images", "tags", "collection", "type"] }); products.sort((a, b) => { const aSales = a.metadata && a.metadata.sales ? a.metadata.sales : 0; const bSales = b.metadata && b.metadata.sales ? b.metadata.sales : 0; return aSales > bSales ? -1 : (aSales < bSales ? 1 : 0); }); return products.slice(0, 4); } </code></pre></div><p>You first use <code class="language-text">this.productService_</code> to retrieve the list of products. Notice that the <code class="language-text">list</code> method can take 2 optional parameters. The first one specifies where conditions, and the second parameter specifies the relations on this products to retrieve.</p><p>Then, you sort the array with the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort">sort</a> Array method giving it a compare function. In the compare function, you compare the number of sales stored inside the <code class="language-text">metadata</code> field. In Medusa, most entities have the <code class="language-text">metadata</code> field which allows you to easily add custom attributes in the default entities for your purposes. Here, you use the <code class="language-text">metadata</code> field to store the number of sales. You are also sorting the products descending.</p><p>Finally, you use the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice">splice</a> Array method to retrieve only the first 5 items.</p><p><strong>Implement updateSales</strong></p><p>Next, you will implement the <code class="language-text">updateSales</code> method in the <code class="language-text">TopProductsService</code>. This method receives an order ID as a parameter, then retrieves this order and loops over the items ordered. Then, the <code class="language-text">sales</code>property inside <code class="language-text">metadata</code> is incremented and the product is updated.</p><p>Add the new method in <code class="language-text">TopProductsService</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">async updateSales(orderId) { const order = await this.orderService_.retrieve(orderId, { relations: ["items", "items.variant", "items.variant.product"] }); if (order.items && order.items.length) { for (let i = 0; i < order.items.length; i++) { const item = order.items[i]; //retrieve product by id const product = await this.productService_.retrieve(item.variant.product.id, { relations: ["variants", "variants.prices", "options", "options.values", "images", "tags", "collection", "type"] }); const sales = product.metadata && product.metadata.sales ? product.metadata.sales : 0; //update product await this.productService_.update(product.id, { metadata: { sales: sales + 1 } }); } } } </code></pre></div><p>You first use <code class="language-text">this.orderService_</code> to retrieve the order by its ID. The <code class="language-text">retrieve</code> method takes the order ID as the first parameter and a config object as the second parameter which is similar to the ones you used in the previous method. You pass it the relations array to retrieve the ordered items and their products.</p><p>Then, you loop over the items and use the product id inside each item to retrieve the product. Afterward, you increment the number of sales and update the product using the <code class="language-text">update</code> method on <code class="language-text">this.productService_</code>.</p><p>This service is now ready to update product sales numbers and retrieve products ordered based on their sales number.</p><h2 id="add-an-api-endpoint">Add an API Endpoint</h2><p>Now, you will add an API endpoint to retrieve the top products. To add an API endpoint, you can do that by creating the file <code class="language-text">src/api/index.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import { Router } from "express" export default () => { const router = Router() router.get("/store/top-products", async (req, res) => { const topProductsService = req.scope.resolve("topProductsService") res.json({ products: await topProductsService.getTopProducts() }) }) return router; } </code></pre></div><p>Creating an endpoint is easy. You just need to export an <a href="https://expressjs.com/">Express</a> Router. This router can hold as many routes as you want.</p><p>In this code, you add a new GET route at the endpoint <code class="language-text">/store/top-products</code>. The reason you are using <code class="language-text">store</code> here as a prefix to <code class="language-text">top-products</code> is that Medusa prefixes all storefront endpoints with <code class="language-text">/store</code>, and all admin endpoints with <code class="language-text">/admin</code>. You do not need to add this prefix, but it is good to follow the conventions of the Medusa APIs.</p><p>In this route, you retrieve the service you created in the previous section with this line:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">const topProductsService = req.scope.resolve("topProductsService") </code></pre></div><p>You can retrieve any service inside routes using <code class="language-text">req.scope.resolve</code>. As explained in the services section, you need to use the camel-case version of the file name followed by <code class="language-text">Service</code> when referencing a service in your code.</p><p>After retrieving the service, you can then use the methods you created on it. So, you return a JSON response that has the key <code class="language-text">products</code> and the value will be the array of top products returned by <code class="language-text">getTopProducts</code>.</p><p>Let us test it out. You can access this endpoint at <code class="language-text">localhost:9000/store/top-products</code>. As this is a GET request, you can do it from your browser or using a client like <a href="https://www.postman.com/">Postman</a> or <a href="https://www.thunderclient.io/">Thunder Client</a>.</p><p>You should see an array of products in the response. At the moment, nothing is sorted as you have not implemented the subscriber which will update the sales number.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jurVzncm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_0E2AAA019E9ECAD398F74CB5188E044A697A4B7712D8B64DE0483D9EA29C0E07_1636115815267_Screen%2BShot%2B2021-11-04%2Bat%2B7.32.44%2BPM.png" class="kg-image" alt="Get started with Medusa Part 2: Make the Server Your Own" loading="lazy"/></figure><h2 id="add-a-subscriber">Add a Subscriber</h2><p>Finally, you will add a subscriber which will update the sales number of products when an order is placed.</p><p>Before creating the subscriber, you need to make sure that Redis is installed and running on your machine. You can test that by running the following command in your terminal:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">redis-cli ping </code></pre></div><p>If the command returns “PONG” then the Redis service is running.</p><p>Then, go to <code class="language-text">Medusa-config.js</code> in the root of your project. You will see that at the end of the file inside the exported config there is this line commented out:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">// redis_url: REDIS_URL, </code></pre></div><p>Remove the comments. This uses the variable <code class="language-text">REDIS_URL</code> declared in the beginning of the file. Its value is either the Redis URL set in <code class="language-text">.env</code> or the default Redis URL <code class="language-text">redis://localhost:6379</code>. If you have a different Redis URL, add the new variable <code class="language-text">REDIS_URL</code> in <code class="language-text">.env</code> with the URL.</p><p>Then, restart the server. This will take the updated configuration and connect to your Redis server.</p><p>Now, you will implement the subscriber. Create the file <code class="language-text">src/subscribers/top-products.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">class TopProductsSubscriber { constructor({ topProductsService, eventBusService }) { this.topProductsService_ = topProductsService; eventBusService.subscribe("order.placed", this.handleTopProducts); } handleTopProducts = async (data) => { this.topProductsService_.updateSales(data.id); }; } export default TopProductsSubscriber; </code></pre></div><p>Similar to how you implemented <code class="language-text">TopProductsService</code>, you pass the <code class="language-text">topProductsService</code> in the constructor using dependency injection. You also pass <code class="language-text">eventBusService</code>. This is used to subscribe a handler to an event in the constructor.</p><p>You subscribe to the order placed event with this line:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">eventBusService.subscribe("order.placed", this.handleTopProducts); </code></pre></div><p>The <code class="language-text">subscribe</code> method on <code class="language-text">eventBusService</code> takes the name of the event as the first parameter and the handler as the second parameter.</p><p>You then define in the class the <code class="language-text">handleTopProducts</code> method which will handle the <code class="language-text">order.placed</code> event. Event handlers in Medusa generally receive a <code class="language-text">data</code>object that holds an <code class="language-text">id</code> property with the ID of the entity this event is related to. So, you pass this ID into the <code class="language-text">updateSales</code> method on <code class="language-text">this.topProductsService_</code> to update the number of sales for each of the products in the order.</p><h2 id="test-it-out">Test It Out</h2><p>You will now test everything out. Make sure the server is running. If not, run it with the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm start </code></pre></div><p>Then, go to the Medusa storefront installation and run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm run dev </code></pre></div><p>Go to the storefront and place an order. This will trigger the <code class="language-text">TopProductsSubscriber</code> which will update the sales of the products in that order.</p><p>Now, send a request to <code class="language-text">/store/top-products</code> like you did before. You should see that <code class="language-text">sales</code> inside the <code class="language-text">metadata</code> property of the products in that order has increased.</p><figure class="kg-card kg-image-card"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z1O23AdW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_0E2AAA019E9ECAD398F74CB5188E044A697A4B7712D8B64DE0483D9EA29C0E07_1636115827468_Screen%2BShot%2B2021-11-05%2Bat%2B1.00.44%2BPM.png" class="kg-image" alt="Get started with Medusa Part 2: Make the Server Your Own" loading="lazy"/></figure><p>Try to add a new product from the admin panel or use the database in <a href="https://github.com/shahednasser/medusa-store-tutorial">the GitHub repository</a> of this tutorial, which has an additional product. Then, try to make more orders with that product. You will see that the sorting in the endpoint has changed based on the number of sales.</p><h2 id="conclusion">Conclusion</h2><p>In this tutorial, you learned how to add custom API endpoint, service, and subscriber. You can use these 3 to implement any custom feature or integration into your store.</p><p>In the next tutorial, you will use the API endpoint you created in this part to customize the frontend and add a product slider that showcases the top selling products on your store.</p><p>In the meantime, should you have any issues or questions related to Medusa, then feel free to reach out to the Medusa team via <a href="https://discord.gg/F87eGuwkTp">Discord</a>.</p>]]></content:encoded></item><item><title><![CDATA[Get started with Medusa Part 1: the open-source alternative to Shopify]]></title><description><![CDATA[Medusa is an open-source headless commerce engine that is fast and customizable. ]]></description><link>https://dev.to/medusajs/get-started-with-medusa-the-open-source-alternative-to-shopify-305j</link><guid isPermaLink="false">Ghost__Post__617563116e5b3510767b3b9b</guid><category><![CDATA[Reviews]]></category><category><![CDATA[eCommerce]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 02 Nov 2021 15:56:55 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/345c585aee719bd71c28795a7d108712/part-2-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/345c585aee719bd71c28795a7d108712/part-2-1.png" alt="Get started with Medusa Part 1: the open-source alternative to Shopify"/><p>There are many popular ecommerce platforms that come to developers’ minds first, and one of these is Shopify. Shopify established itself as one of the go-to platforms to create an ecommerce store for any business. However, it has a lot of disadvantages including the fact that it is not free and it has minimal customizability. This is where Medusa comes in.</p><p><a href="https://www.medusajs.com/">Medusa</a> is an open-source headless commerce engine that is fast and customizable. As Medusa is split into 3 core components - the headless commerce part that exposes the REST APIs for your store, the frontend of your store, and the admin panel - you are free to use the platform as a whole, or use the parts that you need for your ecommerce store.</p><p>In this tutorial series, you will learn how to create an ecommerce store with Medusa. This includes setting up your development environment, adding features and plugins to your backend, frontend, and admin panel each, and everything you might need to set up your ecommerce store with Medusa.</p><p>In this part of the tutorial series, you will learn how to install and run each part of the platform separately, and you will learn the structure of each part to understand where you need to do what. Then, you will learn how to set up all the different parts together with a single command.</p><h2 id="why-medusa"><strong>Why Medusa</strong></h2><h3 id="customization-abilities">Customization Abilities</h3><p>Shopify is a great choice if you are creating a basic store with no need for customization, or you are not a tech-savvy person. However, you should not use Shopify if you are looking to own your tech stack and make changes per your business requirements. When you choose Shopify, you are stuck with the features and architecture that the platform provides out of the box.</p><p>On the other hand, Medusa’s main feature is its flexibility and extendibility. You can use all of the 3 core components together, or take some of them and couple or integrate them with other technologies or systems.</p><p>You can still use it as a whole and you will get a great development and user experience. The backend is built on Node.js, Express, and by default SQLite when you first install the server with the option to use <a href="https://www.postgresql.org/">PostgreSQL</a> and <a href="https://redis.io/">Redis</a>.</p><p>For the frontend, you have the option to use a starter storefront built with either <a href="https://nextjs.org/">Next.js</a> or <a href="https://www.gatsbyjs.com/">Gatsby</a>. As with both options, you will end up with a static website that connects to the headless server, the speed of your website is almost guaranteed to be fast.</p><p>As for the backend, it is also built with Gatsby and connects to your server just like the frontend.</p><p>This sets Medusa apart from other ecommerce platforms that are tightly coupled, complex and slow. Medusa offers a lot of features out of the box and is built to allow you to customize it based on your needs. Compared to Shopify, which provides less ownership over your tech stack, it allows you to completely own your tech stack.</p><p><em>Suggested Read: <a href="https://blog.shahednasser.com/medusa-create-fast-and-highly-customizable-ecommerce-store/">Medusa: Create A Fast and Highly Customizable E-Commerce Store</a></em></p><h3 id="pricing">Pricing</h3><p>Shopify’s pricing models can be a big disadvantage as there are a lot of other alternatives, including Medusa, that offer their ecommerce platform for free.</p><p>Not only do you have to pay to use and deploy the platform, but also it is hard to find plugins or themes for free. In addition, installing plugins is not easy due to the platform’s inflexibility.</p><p>This is where open-source shines. You are free to use and deploy Medusa free of charge. You also have an open-source community backing you up, providing free plugins for you to use. Due to Medusa’s flexibility, installing plugins is very easy.</p><h3 id="business-use-cases">Business Use Cases</h3><p>As mentioned earlier, Shopify is not flexible and is hard to customize. This means that a lot of business use cases, including B2B, market places, custom shopping experiences, and more are not available or possible with Shopify.</p><p>If you are sure that your business will just sell products with the conventional ecommerce experience, that might not be a problem for you. However, if you are already planning for the growth of your business and need an ecommerce platform that can grow and extend as needed with your business use cases, then choosing Shopify will prove to be a hassle.</p><p>Medusa’s headless APIs and flexibility allow you to easily create plugins to customize the shopping experience to your use case or integrate Medusa with other services as needed.</p><h2 id="prerequisites">Prerequisites</h2><p>Before we start, make sure you install <a href="https://nodejs.org/en/">Node.js</a> if you have not. You will also need <a href="https://www.npmjs.com/">NPM</a> but it will install with Node.js when you install it.</p><p>To check if you have Node.js and NPM installed you can run these commands:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">node</span> -v <span class="token function">npm</span> -v</code></pre></div><p>If the output of each of the commands shows a number version, then you have them installed. Otherwise, you need to install them.</p><h2 id="set-up-medusa">Set Up Medusa</h2><p>At its core, Medusa is the backend that exposes the REST APIs, which will allow your frontend or admin panel to retrieve or modify the data. You can replace the storefront or admin panel with a platform of your own that connects to the APIs, but you at least need this part of Medusa in your system.</p><h3 id="install-medusa">Install Medusa</h3><p>Installing Medusa is easy. First, you need to install the CLI tool that allows you to set up the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> -g @medusajs/medusa-cli</code></pre></div><p>Once this part is done, you can use the CLI to set up a new Medusa store on your machine:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">medusa new my-store --seed</code></pre></div><p>This will create a new Medusa installation in the directory <code class="language-text">my-store</code>. You can change the name of the store or directory by changing <code class="language-text">my-store</code>. By applying the <code class="language-text">--seed</code> option, it will seed the database with basic data including a demo product.</p><h3 id="run-medusa">Run Medusa</h3><p>Once this command is done, you are ready to run your server! First, change to the directory of the medusa store:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> my-store</code></pre></div><p>Then, run the <code class="language-text">develop</code> command using the CLI tool to run the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">medusa develop</code></pre></div><p>This will run the server by default at <code class="language-text">localhost:9000</code>. You can test it by going to <code class="language-text">localhost:9000/store/products</code> in your browser and you should see a JSON array of products. It will include just one product as the seeder adds just one.</p><p>You can check the full list of <a href="https://docs.medusa-commerce.com/api/store/auth">API endpoints in the documentation</a>. For the storefront, all endpoints are prefixed with <code class="language-text">/store</code>, whereas for the admin panel, all endpoints are prefixed with <code class="language-text">/admin</code>.</p><h3 id="structure-overview">Structure Overview</h3><p>Let's take a look at the directory structure for the server. It should look something like this:</p><p>As you can see we have the following directories:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-24-at-5.43.48-PM-1.png" class="kg-image" alt="Get started with Medusa Part 1: the open-source alternative to Shopify" loading="lazy" width="540" height="656"/></figure><ol><li><code class="language-text">data</code>: This directory holds the data that will be used to seed the database. It has the file <code class="language-text">seed.json</code> which includes the configuration for the basic store. These data are the data added to your store when you add the <code class="language-text">--seed</code> option which we did.</li><li><code class="language-text">dist</code>: This directory will hold the build of your server when you run <code class="language-text">npm run build</code>. When you deploy your server you will run this command and the compiled files in the <code class="language-text">dist</code> directory will be used.</li><li><code class="language-text">src</code>: Inside the <code class="language-text">src</code> directory you can add any of the plugins or changes you might need to make. Inside the <code class="language-text">api</code> subdirectory, you can add new endpoints to your store. Inside the <code class="language-text">services</code> subdirectory, you can add new services which you can use globally in different endpoints. Inside the <code class="language-text">subscribers</code> subdirectory, you can add event listeners to different events like when an order is placed.</li><li><code class="language-text">uploads</code>: will include any files to be uploaded like product images.</li></ol><h2 id="set-up-the-storefront">Set Up the Storefront</h2><p>Next, we'll install and set up the storefront. As mentioned earlier, you can use the <a href="https://github.com/medusajs/gatsby-starter-medusa">Gatsby</a> starter or <a href="https://github.com/medusajs/nextjs-starter-medusa">Next.js</a> starter. For this tutorial, we'll use the Next.js starter.</p><h3 id="install-the-storefront">Install the Storefront</h3><p>To install the Next.js storefront just run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-next-app -e https://github.com/medusajs/nextjs-starter-medusa my-storefront</code></pre></div><p>This will create a Next.js storefront in the directory <code class="language-text">my-storefront</code>. If you to name it something else you can change the name in the command.</p><h3 id="run-the-storefront">Run the Storefront</h3><p>Before running the storefront, make sure that the server is running first as the storefront will connect to the server to retrieve the data of the store. To run the server, you can follow the steps in the previous section.</p><p>To run the storefront, first change to the directory of the storefront:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> my-storefront</code></pre></div><p>Then, run the following command to run the storefront:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> run dev</code></pre></div><p>This will run the storefront at <code class="language-text">localhost:8000</code> by default. If you open it, you should see a basic storefront with links to different documentations. You can also see the products and try out the full checkout experience.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-24-at-6.21.27-PM.png" class="kg-image" alt="Get started with Medusa Part 1: the open-source alternative to Shopify" loading="lazy" width="2000" height="1164" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-24-at-6.21.27-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-24-at-6.21.27-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-24-at-6.21.27-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-24-at-6.21.27-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><h3 id="add-stripe-integration">Add Stripe Integration</h3><p>To add the <a href="https://stripe.com">Stripe</a> integration, first copy the <code class="language-text">.env.template</code> to <code class="language-text">.env.local</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">mv</span> .env.template .env.local</code></pre></div><p>Then, change the environment variable for Stripe's public key:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token assign-left variable">NEXT_PUBLIC_STRIPE_KEY</span><span class="token operator">=</span>pk_test_something</code></pre></div><h3 id="structure-overview-1">Structure Overview</h3><p>The structure of the directory should look like this:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-24-at-6.25.24-PM.png" class="kg-image" alt="Get started with Medusa Part 1: the open-source alternative to Shopify" loading="lazy" width="536" height="728"/></figure><ol><li><code class="language-text">components</code>: This directory includes different components in the storefront like the cart, checkout, navigation bar, and more. Here you can make changes to the components if needed.</li><li><code class="language-text">context</code>: This includes some easy to toggle or change settings for your store through the context. For example, you can toggle showing the full cart in <code class="language-text">context/display-context.js</code> by changing the value of <code class="language-text">cartView</code> in the <code class="language-text">defaultDisplayContext</code> object.</li><li><code class="language-text">pages</code>: This includes the different pages in the storefront. By default, the storefront will have 3 pages: Checkout, Product page, and landing page. You can add more pages to your store here.</li><li><code class="language-text">public</code>: You can add the public assets like images here.</li><li><code class="language-text">styles</code>: This directory holds all the styles of the store and you can make changes here to change the styles of the storefront.</li><li><code class="language-text">utils</code>: This includes helper functions like getting Stripe's public key, helper functions, configurations, and more.</li></ol><h2 id="set-up-the-admin-panel">Set Up the Admin Panel</h2><p>Finally, we'll install and set up the admin panel. The admin panel is built with Gatsby. Through the admin panel, you can use the APIs exposed by the server to view or make changes to the data in the store. This includes viewing and adding products, orders, customers, and more.</p><h3 id="install-the-admin-panel">Install the Admin Panel</h3><p>To set up the admin panel, first, clone <a href="https://github.com/medusajs/admin">the repository of the admin panel</a>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">git</span> clone https://github.com/medusajs/admin my-admin</code></pre></div><p>Then, change to the directory of the admin panel, which is <code class="language-text">my-admin</code>. You can change that by changing it in the command above.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> my-admin</code></pre></div><p>After that, you need to install the dependencies with NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span></code></pre></div><h3 id="run-the-admin-panel">Run the Admin Panel</h3><p>Once all the dependencies are installed, we're ready to run the admin panel:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>This will open the admin panel at <code class="language-text">localhost:7000</code> by default. When you first open it, you will be asked to log in. To log in you can use the email "admin@medusa-test.com" with the password "supersecret".</p><p>When you log in, you will see an admin panel with a sidebar that you can use to view orders, customers, products, and more.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-24-at-9.48.55-PM.png" class="kg-image" alt="Get started with Medusa Part 1: the open-source alternative to Shopify" loading="lazy" width="2000" height="765" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-24-at-9.48.55-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-24-at-9.48.55-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-24-at-9.48.55-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-24-at-9.48.55-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><h3 id="structure-overview-2">Structure Overview</h3><p>The structure of the directory should look something like this:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-24-at-9.50.05-PM.png" class="kg-image" alt="Get started with Medusa Part 1: the open-source alternative to Shopify" loading="lazy" width="546" height="916"/></figure><ol><li><code class="language-text">src</code>: Here you will find the main code for the admin panel. You can edit components, pages, context, and more. Any edits or additions to the admin panel can be done here.</li><li><code class="language-text">public</code>: This will include the build generated by Gatsby for the admin panel.</li><li><code class="language-text">static</code>: The public static assets you will need for the admin panel like images.</li></ol><p>As mentioned, this admin panel is built with Gatsby. Although you don't necessarily need to learn Gatsby to set it up and run it, making changes to it would require some understanding of how Gatsby works, depending on the kind of change you will be making.</p><h2 id="alternative-solution-create-medusa-app">Alternative Solution: Create Medusa App</h2><p>As mentioned, Medusa decouples the three core components of the platform to give you the flexibility and ability to customize the platform as fitting for you. However, if you will use the three components, you can install them all at once.</p><p>Medusa introduces <a href="https://docs.medusa-commerce.com/how-to/create-medusa-app">create-medusa-app</a>. If you've used <a href="https://reactjs.org">React</a> before, you will notice that this is similar to <a href="https://create-react-app.dev">create-react-app</a>. by using this tool, you will be able to set up the 3 components of the platform all at once.</p><h3 id="set-up-medusa-app">Set Up Medusa App</h3><p>In your terminal, you just need to run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-medusa-app</code></pre></div><p>You will then be asked some questions related to naming your store, what technologies you want to use for the different parts of the platform, and more.</p><p>Once the installation is done, you will have 3 directories ready. One for the server which will be called <code class="language-text">backend</code>, one for the storefront which will be called <code class="language-text">storefront</code>, and one for the admin which will be called <code class="language-text">admin</code>.</p><h3 id="run-the-medusa-app">Run the Medusa App</h3><p>Similar to the instructions of each component in the first method, when we install them separately, you will have to run each component separately.</p><p>The Medusa server is required for both the storefront and the admin panel, so make sure that it's running before running either of them.</p><p>To run the Medusa server you need to change to the <code class="language-text">backend</code> directory then run it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> backend <span class="token function">npm</span> start</code></pre></div><p>To run the Medusa storefront you need to change to the <code class="language-text">storefront</code> directory then run it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> storefront <span class="token function">npm</span> start</code></pre></div><p>To run the Medusa admin you need to change to the <code class="language-text">admin</code> directory then run it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">cd admin npm start</code></pre></div><h2 id="conclusion">Conclusion</h2><p>Although no one can deny Shopify’s popularity and many advantages, it’s also good to recognize some of its disadvantages and what other options or alternatives you have. Its lack of extendibility and ownership are disadvantages that should not be taken lightly when choosing an ecommerce platform for your system.</p><p>Medusa is a great alternative when it comes to these cons. Medusa is an open-source platform that will provide you with an extensible and fast development experience, as you have probably seen from this tutorial. Its setup is quick, and you can easily make changes or additions to any part of its components.</p><p>In addition to all that, the team behind Medusa is always happy to assist you with any questions you might have regarding how to set up Medusa on <a href="https://discord.gg/F87eGuwkTp">their Discord</a>!</p><p>In the next part of the series, you will see how to make changes to the server. This includes how to add API endpoints, services, and more. As we go through the tutorial series you will be able to master and understand each component of Medusa to help you build your ecommerce store.</p>]]></content:encoded></item><item><title><![CDATA[Strapi Tutorial: Build a Blog with Next.js]]></title><description><![CDATA[Learn how to set up Strapi from scratch, and how to use starters to create a blog.]]></description><link>https://blog.shahednasser.com/strapi-tutorial-build-a-blog-with-next-js/</link><guid isPermaLink="false">Ghost__Post__617a615c7ec5e905d9bde6db</guid><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 01 Nov 2021 10:13:21 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/7ba78ca821fb59c20235977dcf45de59/bram-naus-n8Qb1ZAkK88-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/7ba78ca821fb59c20235977dcf45de59/bram-naus-n8Qb1ZAkK88-unsplash-2.jpg" alt="Strapi Tutorial: Build a Blog with Next.js"/><p>If you want to start your own blog, or just want to learn a cool CMS platform, then you should check out <a href="https://strapi.io">Strapi</a>. Strapi is an open-source Node.js headless CMS. This means that you set up Strapi and plug it into any frontend or system you have.</p><p>In this tutorial we'll first look at why you should use Strapi, how to set it up from scratch, then we'll use one of Strapi's starters to easily create a blog with Next.js.</p><h2 id="why-strapi">Why Strapi</h2><p>Headless APIs provide you with a lot of flexibility. When you want to develop a system with different components, you don't have to worry about finding one framework or programming language that you can use to be able to implement all the components.</p><p>Strapi allows you to integrate CMS into your projects regardless of what they are. Whether you want to add CMS to your e-commerce store, build a blog, or any other use case that requires CMS, you can easily use Strapi to build the CMS part, then use its APIs to integrate it into your system.</p><p>What sets Strapi apart is that it's fully customizable. You are not bound to a database schema or data structure. Once you set up Strapi, you are free to create your own models and c0llections as fit your needs. This makes setting up your CMS much easier and allows you to focus on creating the front-end.</p><h2 id="set-up-strapi">Set Up Strapi</h2><p>In this section, you'll learn how to set up Strapi from scratch. This allows you to understand better how it works and what are the different elements to it. In the next section, you'll be using a Strapi starter blog that does all the heavy lifting for you.</p><h3 id="install-strapi">Install Strapi</h3><p>The first step is to install Strapi. You can do that with this command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-strapi-app strapi-blog --quickstart</code></pre></div><h3 id="register-as-admin">Register as Admin</h3><p>Once the installation is complete, a tab will open in your default browser and it will be a registration form. You will need to fill out your information as an admin user.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-28-at-10.40.36-AM.png" class="kg-image" alt="Strapi Tutorial: Build a Blog with Next.js" loading="lazy" width="1082" height="1352" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-28-at-10.40.36-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-28-at-10.40.36-AM.png 1000w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-28-at-10.40.36-AM.png 1082w" sizes="(min-width: 720px) 720px"/></figure><p>Once you're done, you'll be logged into your dashboard.</p><h3 id="create-a-content-type">Create a Content-Type</h3><p>Let's say you're creating the blog's database yourself. You'll need to create a <code class="language-text">posts</code> table that stores all the posts you'll create.</p><p>In Strapi, you create Content-Types. In these Content-Types, you can add any kind of field you would to the table.</p><p>On your dashboard, you should see "Create Your First Content-Type". Click on it.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-28-at-10.42.06-AM.png" class="kg-image" alt="Strapi Tutorial: Build a Blog with Next.js" loading="lazy" width="1586" height="834" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-28-at-10.42.06-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-28-at-10.42.06-AM.png 1000w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-28-at-10.42.06-AM.png 1586w" sizes="(min-width: 720px) 720px"/></figure><p>Then, a pop-up will appear asking you to name the Content-Type. Content-Types are named in the singular form in Strapi. So, enter <code class="language-text">post</code> in the Display Name field then click Continue.</p><p>After that, you'll need to add some fields to the Content-Type. You'll see that there are many to choose from.</p><p>Add the following fields to the Post Content-Type:</p><ol><li><code class="language-text">title</code> of type Text. You can set it to required by clicking on the Advanced Settings Tab and checking the required checkbox.</li><li><code class="language-text">content</code> of type Rich text. You should also set it to required.</li><li><code class="language-text">admin_user</code> this will be a Relation type. You'll link it to the User Content-Type.</li><li><code class="language-text">date_created</code> this will be a Date field of type Datetime. You can also set it to required.</li><li><code class="language-text">file</code> this will be a Relation type as well to the File Content-Type. We can use it to add an image to the post</li></ol><p>Once done, the Post Content-Type should look like this:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-28-at-11.00.42-AM.png" class="kg-image" alt="Strapi Tutorial: Build a Blog with Next.js" loading="lazy" width="1756" height="1022" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-28-at-11.00.42-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-28-at-11.00.42-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-28-at-11.00.42-AM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-28-at-11.00.42-AM.png 1756w" sizes="(min-width: 720px) 720px"/></figure><p>Click <em>Save, </em>and the new Content-Type will be added successfully.</p><h3 id="set-permissions">Set Permissions</h3><p>Next, you'll set permissions to allow users to access the posts. To do that, in the sidebar go to Settings, then go to Roles under Users & Permissions.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-28-at-11.01.31-AM.png" class="kg-image" alt="Strapi Tutorial: Build a Blog with Next.js" loading="lazy" width="1016" height="1620" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-28-at-11.01.31-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-28-at-11.01.31-AM.png 1000w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-28-at-11.01.31-AM.png 1016w" sizes="(min-width: 720px) 720px"/></figure><p>There, choose Public, then scroll down to Permissions and select all permissions.</p><h3 id="making-requests">Making Requests</h3><p>If you now try sending a GET request to <code class="language-text">localhost:1337/posts</code> you'll see an empty array.</p><p>In Strapi, once you create a Content-Type, you'll have the following API requests ready for use:</p><ol><li>GET <code class="language-text">/posts</code>: Get the list of items in the Content-Type.</li><li>GET <code class="language-text">/posts/{id}</code>: Get the item having id <code class="language-text">{id}</code>.</li><li>GET <code class="language-text">/posts/count</code>: Get the number of items in the Content-Type.</li><li>POST <code class="language-text">/posts</code>: Create a new post.</li><li>DELETE <code class="language-text">/posts/{id}</code>: Delete a post of id <code class="language-text">{id}</code>.</li><li>PUT <code class="language-text">/posts/{id}</code>: Update a post of id <code class="language-text">{id}</code>.</li></ol><p>Note that we use the plural form of the Content-Type in the requests.</p><p>As we can see, Strapi makes it easy to create Content-Types on the fly and once you do you can start accessing them with the REST API right away.</p><h2 id="using-strapi-starters">Using Strapi Starters</h2><p>There are <a href="https://strapi.io/starters">many starters</a> for Strapi for different languages and frameworks. Starters allow you to start with a certain template with ready front-end or a configured Strapi instance with the Content-Type required for the template. This saves you time rebuilding or reconfiguring the same project ideas.</p><p>In this section, you'll create a blog using Strapi starters. We'll use Next.js for the front-end.</p><h3 id="set-up-nextjs-starter">Set Up Next.js Starter</h3><p>To create a Strapi blog with Next.js, you can use <a href="https://github.com/strapi/strapi-starter-next-blog">strapi-starter-next-blog</a>. It comes with both a Strapi installation ready with the necessary Content-Types which are Article and Category.</p><p>In your terminal run the following command to install it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-strapi-starter strapi-next-blog next-blog</code></pre></div><p>This will install inside a directory called <code class="language-text">strapi-next-blog</code> 2 directories. One called <code class="language-text">backend</code>, which includes the Strapi installation, and one called <code class="language-text">frontend</code>, which includes the Next.js installation.</p><p>Once the installation is done, change to the <code class="language-text">frontend</code> directory then run both Strapi and Next.js with one command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> run develop</code></pre></div><p>This will run Strapi on <code class="language-text">localhost:1337</code> and Next.js on <code class="language-text">localhost:3000</code>.</p><p>If the browser was not opened with to the Strapi dashboard, go to <code class="language-text">localhost:1337/admin/auth/register-admin</code> and register as a new user just like you did before. </p><p>When you are redirected to the dashboard, you'll see that there are already Content-Types and Collections for these types ready.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-28-at-1.50.01-PM-1.png" class="kg-image" alt="Strapi Tutorial: Build a Blog with Next.js" loading="lazy" width="466" height="370"/></figure><p>If you go to each of them you'll see that there are already demo data available.</p><p>Now, to check the frontend, go to <code class="language-text">localhost:3000</code>. You'll see a blog with some blog posts ready.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-28-at-2.11.04-PM.png" class="kg-image" alt="Strapi Tutorial: Build a Blog with Next.js" loading="lazy" width="2000" height="1126" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-28-at-2.11.04-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-28-at-2.11.04-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-28-at-2.11.04-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-28-at-2.11.04-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>And that's it! You can now post stories on the Strapi dashboard and see them on your Next.js frontend. With one command, you were able to create a blog.</p><h2 id="conclusion">Conclusion</h2><p>Strapi is a fully customizable CMS that makes it easier for you to integrate CMS into your systems or websites, as well as use it to create CMS platforms.</p><p>After following along with this tutorial, you should check out more of Strapi's <a href="https://strapi.io/documentation/developer-docs/latest/developer-resources/content-api/content-api.html#api-endpoints">Content API documentation</a> to learn more about how you can access the content types and more.</p>]]></content:encoded></item><item><title><![CDATA[Why Video Marketing Is So Powerful In 2021]]></title><description><![CDATA[Video marketing turned from a singular marketing technique to a full-fledged business strategy.]]></description><link>https://blog.shahednasser.com/why-video-marketing-is-so-powerful-in-2021/</link><guid isPermaLink="false">Ghost__Post__617b981e7ec5e905d9bde7c0</guid><category><![CDATA[Business]]></category><category><![CDATA[Marketing]]></category><dc:creator><![CDATA[Mohd Zaid Mansoori]]></dc:creator><pubDate>Fri, 29 Oct 2021 06:47:56 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/dc29e9c5131139effdf1529214a43899/alexander-shatov-niUkImZcSP8-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/dc29e9c5131139effdf1529214a43899/alexander-shatov-niUkImZcSP8-unsplash-2.jpg" alt="Why Video Marketing Is So Powerful In 2021"/><p>Did you know? Video content is considered one of the most important marketing strategies today. It has revolutionized the marketing techniques on all social media platforms. How did this happen? Video marketing turned from a singular <a href="https://www.searchenginejournal.com/video-marketing-strategy-tips/351958/">marketing technique</a> to a full-fledged business strategy. Normally, various people are involved in creating a video, which means you should keep in mind a few points to craft the perfect video.</p><h2 id="why-is-video-marketing-powerful">Why is Video Marketing Powerful?</h2><p>Finding the answers to the above questions helps formulate an effective <a href="https://www.flyingvgroup.com/blog/2021/05/06/7-key-trends-in-digital-video-advertising-for-2021-cs/">video advertising plan</a> to transform the business. However, we all know that video content is one of the powerful mediums to spread awareness about your brand. Nowadays, people want effortless, fast information, and there is nothing better than a short video. We have listed down a few reasons why video marketing has become a powerful tool in 2021:</p><h3 id="boost-sales-and-increase-conversions"><strong>Boost Sales and Increase Conversions</strong></h3><p>Videos are not created for entertainment purposes. Now, people have started to put videos on the landing page. This leads directly to sales. It is because people who have seen the explanatory video tend to purchase the products. So, are you ready to get started?</p><h3 id="sense-of-physical-existence"><strong>Sense of Physical Existence</strong></h3><p>The content marketing goal is to create long and lasting relationships between the customer and the company. Did you know? Videos tend to offer trust among potential customers and viewers. Although many people remain skeptical regarding buying stuff online, video marketing gives them confidence towards the seller. This is because a video gives you powerful leverage by creating a sense of your business among the customer's minds.</p><h3 id="video-provides-great-roi"><strong>Video provides great ROI</strong></h3><p>Many businesses feel that video content generates a great ROI. There are various <a href="https://invideo.io/">video editor</a> tools available that help in generating great video content. Plus, many editing tools have become more affordable and user-friendly, giving brands hands-on over creating video content. Thus, you should keep in mind that the video you create about your brand effectively describes the services and products you provide. After that, you are off to a great start!</p><h3 id="because-google-loves-videos"><strong>Because Google Loves Videos</strong></h3><p>Google is the king of search engines and owns YouTube. Thus, a trending video on YouTube would be shown on the first page of Google. So, a video that has received significant popularity rises on the search engine rankings. It is all-important to place a video on your site's landing page, as there are high chances to be ranked on the first page of Google. Plus, video ads increase the time a customer spends on your website. And as you know, the longer a customer spends time on your site, the site session increases leading to better ad ranking.</p><h3 id="video-marketing-explains-everything"><strong>Video Marketing Explains Everything </strong></h3><p>Video advertisements give a better understanding of your products and services to the users. This boosts sales with overall customer satisfaction and helps the brand in generating leads. Videos are easily understandable, short, and entertaining. Further video content provides immediate engagement. It provides businesses to bring stale data to life by educating their team. Videos help in demonstrating the potential of the brand to the target audience. Undoubtedly video marketing is the key to ensuring that the customers understand your products and services!</p><h3 id="mobile-users-enjoys-video"><strong>Mobile Users Enjoys Video</strong></h3><p>As we all know, mobile use is skyrocketing, and many videos are played on mobile devices. The point is that mobile video is rising to take an important role in influencing and increasing the sales process. Thus, one good reason to dive into mobile marketing is that the potential customers or the users love it. So what are you waiting for? Create a perfect video for your website and upload it on your social media to generate more leads.</p><h3 id="video-engage-the-lazy-buyers"><strong>Video Engage the Lazy Buyers</strong></h3><p>One thing that is for sure is, video is super easy to understand. The ease of understanding the videos has increased in the past many years. Also, we tend to remember visual content better than words. So, if you want to give a message to your customers, choose video as your medium.</p><h3 id="move-in-before-your-competitor"><strong>Move-in Before your Competitor</strong></h3><p>Various digital marketers now believe that video content is a part of the marketing strategy for a brand. There are several mountains of benefits video content brings to an advertising campaign.</p><p>Create a killer video using your favorite video editor<strong> </strong>tools to get maximum leads. That's why using the best practices and follow-ups, it becomes important to stand out in the crowd. Also, keep in mind that good quality content with great views is better than videos with minimal views. It requires a strategy to create optimal video content as it will help you by boosting visibility and being recognized as a reliable source in front of viewers.</p><h3 id="video-marketing-available-everywhere-and-every-time"><strong>Video Marketing Available Everywhere and Every time</strong><br/></h3><p>Video content is adapting and engaging, but it is quite easy to consume on the go. With the rise in social media platforms, it is no secret that people love to watch videos. Mobile video views and YouTube consumption has increased with time. It is a vital marketing tool to reach a large client base because it is accessible to the laziest of the viewer anytime and anywhere.</p><h3 id="animated-video-ads"><strong>Animated Video Ads</strong><br/></h3><p>Animated video has again gained popularity in recent times. They are cost-effective, easy to maintain, and help in accentuating the key points. There are multiple benefits of animated videos as it provides benefits of visual marketing.</p><h2 id="conclusion">Conclusion<br/></h2><p>There are numerous advantages of using video content for marketing a brand's product and services. It is time for businesses to introduce video marketing in their marketing plan seriously. It increases the conversion rate by diving into sales and helps with visibility on social media platforms. What are you waiting for? Use a good video editor app and create an amazing video describing your products and services to generate leads.</p>]]></content:encoded></item><item><title><![CDATA[Knex.js Tutorial For Beginners]]></title><description><![CDATA[In this tutorial, you'll learn how to use Knex.js with Node.js and Express.]]></description><link>https://blog.shahednasser.com/knex-js-tutorial-for-beginners/</link><guid isPermaLink="false">Ghost__Post__617844cc6e5b3510767b3db0</guid><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 28 Oct 2021 11:54:53 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/f8f8d5de670173955d2c45ed7f01189c/goran-ivos-wJpl8D38Tq8-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/f8f8d5de670173955d2c45ed7f01189c/goran-ivos-wJpl8D38Tq8-unsplash-2.jpg" alt="Knex.js Tutorial For Beginners"/><p><a href="https://knexjs.org">Knex.js</a> is a SQL Query Builder for JavaScript. What it does is that it provides easy to use interface to access a database and perform actions on it and its data. It supports many database management systems like MySQL, SQLite, Postgres, and more.</p><p>With Knex.js, you can have all your configurations for your different environments in one file. Then, you can use the library's methods to perform actions against your database. So, regardless of what database management system you're running for different environments, you can use the same methods.</p><p>In this tutorial, you'll learn how to use Knex.js with Node.js and Express. We'll create migrations, seeders, then query and insert data with Knex.js.</p><p>You can find the code for this tutorial in <a href="https://github.com/shahednasser/knex-tutorial">this GitHub repository</a>.</p><h2 id="prerequisites">Prerequisites</h2><p>Before we start, make sure you have <a href="https://nodejs.org/en/">Node.js</a> installed along with <a href="https://www.npmjs.com">NPM</a>. NPM is installed with Node.js by default, so you just need to install Node.js</p><p>To check if you have it installed, run the following commands:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">node</span> -v <span class="token function">npm</span> -v</code></pre></div><p>If the output is a version, then they're installed on your machine.</p><h2 id="set-up-project">Set Up Project</h2><p>The first step is to set up the project. Open a terminal and create a directory to place the project inside:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> knex-tutorial</code></pre></div><p>Then change to that directory:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> knex-tutorial</code></pre></div><p>Once inside the directory, run the following command to initialize the project with NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> init -y</code></pre></div><p>The option <code class="language-text">-y</code> is added to fill the generated <code class="language-text">package.json</code> with default values.</p><p>The next step is to install the dependencies needed for this tutorial:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i express body-parser knex nodemon</code></pre></div><p>With the command above you'll install <a href="https://expressjs.com">Express</a>, which is what we'll use to build the server; <a href="https://expressjs.com/en/resources/middleware/body-parser.html">body-parser</a>, which is used in Express to parse body parameters; knex for Knex.js; and <a href="https://www.npmjs.com/package/nodemon">nodemon</a>, which is used to watch changes and restart the server.</p><p>Now, create the file <code class="language-text">index.js</code> in the root and add the following content in it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'express'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> bodyParser <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'body-parser'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> port <span class="token operator">=</span> <span class="token number">3000</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>bodyParser<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">'Hello World!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span>port<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Example app listening at http://localhost:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>port<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This will create a simple server with Express.</p><p>Finally, add the <code class="language-text">start</code> script in <code class="language-text">scripts</code> in <code class="language-text">package.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"start"</span><span class="token operator">:</span> <span class="token string">"NODE_ENV=development nodemon index.js"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>Now, you can run the server with the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>You can test the server by going to <code class="language-text">localhost:3000</code>. You should see "Hello, World".</p><h2 id="set-up-knexjs">Set Up Knex.js</h2><p>In this section, you'll set up and configure Knex.js.</p><p>Knex.js has a CLI you can use to create migrations, seeders, and more. So, start by installing it globally:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i -g knex</code></pre></div><p>After the installation is done, you can start making use of the CLI.</p><p>The first step in initializing Knex.js is to create the <code class="language-text">knexfile</code>. The <code class="language-text">knexfile</code> is a file that contains the configuration for Knex.js, including which database client to use for each environment and the connection configuration.</p><p>Create the <code class="language-text">db</code> directory which will hold all files related to the database setup:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> db</code></pre></div><p>Then, change to the <code class="language-text">db</code> directory:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> db</code></pre></div><p>Inside the directory, run the following command to create <code class="language-text">knexfile.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">knex init</code></pre></div><p>This will create <code class="language-text">knexfile.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token comment">// Update with your config settings.</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">development</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">client</span><span class="token operator">:</span> <span class="token string">'sqlite3'</span><span class="token punctuation">,</span> <span class="token literal-property property">connection</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">filename</span><span class="token operator">:</span> <span class="token string">'./dev.sqlite3'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">staging</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">client</span><span class="token operator">:</span> <span class="token string">'postgresql'</span><span class="token punctuation">,</span> <span class="token literal-property property">connection</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">database</span><span class="token operator">:</span> <span class="token string">'my_db'</span><span class="token punctuation">,</span> <span class="token literal-property property">user</span><span class="token operator">:</span> <span class="token string">'username'</span><span class="token punctuation">,</span> <span class="token literal-property property">password</span><span class="token operator">:</span> <span class="token string">'password'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">pool</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">min</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token literal-property property">max</span><span class="token operator">:</span> <span class="token number">10</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">migrations</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">tableName</span><span class="token operator">:</span> <span class="token string">'knex_migrations'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">production</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">client</span><span class="token operator">:</span> <span class="token string">'postgresql'</span><span class="token punctuation">,</span> <span class="token literal-property property">connection</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">database</span><span class="token operator">:</span> <span class="token string">'my_db'</span><span class="token punctuation">,</span> <span class="token literal-property property">user</span><span class="token operator">:</span> <span class="token string">'username'</span><span class="token punctuation">,</span> <span class="token literal-property property">password</span><span class="token operator">:</span> <span class="token string">'password'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">pool</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">min</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token literal-property property">max</span><span class="token operator">:</span> <span class="token number">10</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">migrations</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">tableName</span><span class="token operator">:</span> <span class="token string">'knex_migrations'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div><p>As you can see, it exports configuration for the development, staging, and production environments. You can specify the client to use and the connection details for each environment.</p><p>In this tutorial, we'll just cover setting up the development environment using <a href="https://www.sqlite.org/index.html">SQLite</a>. However, if you are interested in setting up another DB management system, you can follow along but refer to <a href="https://knexjs.org">Knex.js's documentation</a> to understand how you should set up your connection to your database.</p><p>Replace the content of <code class="language-text">knexfile.js</code> with the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Update with your config settings.</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">development</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">client</span><span class="token operator">:</span> <span class="token string">'sqlite3'</span><span class="token punctuation">,</span> <span class="token literal-property property">connection</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">filename</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'db.sqlite3'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">migrations</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">tableName</span><span class="token operator">:</span> <span class="token string">'knex_migrations'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">useNullAsDefault</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div><p>This will use <code class="language-text">sqlite3</code> for the development environment. Unlike other DB management systems, you just need to specify the file name for SQLite.</p><p>This configuration also specifies that the database should have a table called <code class="language-text">knex_migrations</code> to keep track of the migrations. As for <code class="language-text">useNullAsDefault</code>, it's necessary for SQLite configuration if you have columns that you want to default to Null.</p><p>As you are using <code class="language-text">sqlite3</code>, you need to install its library:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> sqlite3</code></pre></div><p>If you're using another DB management system, then you need to install its library instead.</p><p>Finally, go back to <code class="language-text">index.js</code> in the root and add the following to add the configuration when the server runs:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> knexConfig <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./db/knexfile'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//initialize knex</span> <span class="token keyword">const</span> knex <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'knex'</span><span class="token punctuation">)</span><span class="token punctuation">(</span>knexConfig<span class="token punctuation">[</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">NODE_ENV</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre></div><p>This initializes knex based on the current environment.</p><h2 id="create-a-migration">Create a Migration</h2><p>Migration allows you to easily modify a database schema. Inside each migration, you'll have 2 functions: <code class="language-text">up</code> is executed when the migration runs, whereas <code class="language-text">down</code> is executed the migration is rolled back. This means when you don't need the changes that were done by the migration anymore.</p><p>Before you create a migration, make sure you're still in the <code class="language-text">db</code> directory.</p><p>Then, inside that directory run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">knex migrate:make create_users_table</code></pre></div><p>This will create a migration file inside a directory that knex will create called <code class="language-text">migrations</code>. If you open it, you'll see that there are already <code class="language-text">up</code> and <code class="language-text">down</code> functions.</p><p>Replace the content of the file with the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"> exports<span class="token punctuation">.</span><span class="token function-variable function">up</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">knex</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> knex<span class="token punctuation">.</span>schema <span class="token punctuation">.</span><span class="token function">createTable</span><span class="token punctuation">(</span><span class="token string">'users'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">table</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> table<span class="token punctuation">.</span><span class="token function">increments</span><span class="token punctuation">(</span><span class="token string">'id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> table<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token string">'name'</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">notNullable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> table<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token string">'email'</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">;</span> table<span class="token punctuation">.</span><span class="token function">timestamps</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> exports<span class="token punctuation">.</span><span class="token function-variable function">down</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">knex</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> knex<span class="token punctuation">.</span>schema <span class="token punctuation">.</span><span class="token function">dropTable</span><span class="token punctuation">(</span><span class="token string">'users'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> </code></pre></div><p>Inside the <code class="language-text">up</code> function, a new table called <code class="language-text">users</code> is created. The table has an auto-increment column <code class="language-text">id</code>, string columns <code class="language-text">name</code> and <code class="language-text">email</code>, and timestamp columns which by default are <code class="language-text">created_at</code> and <code class="language-text">updated_at</code>.</p><p>Inside the <code class="language-text">down</code> function, the table is dropped. This means that when you don't want the <code class="language-text">users</code> table anymore, you just <a href="https://knexjs.org/#Migrations-rollback">rollback</a> the migration.</p><p>Now, go to <code class="language-text">package.json</code> in the root of the project and the <code class="language-text">migrate</code> script inside <code class="language-text">scripts</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"migrate"</span><span class="token operator">:</span> <span class="token string">"knex migrate:latest --knexfile db/knexfile.js"</span></code></pre></div><p>This script uses Knex's CLI command <code class="language-text">migrate:latest</code> to migrate the latest migrations that have not been migrated yet. The option <code class="language-text">--knexfile</code> specifies the location of the knexfile.</p><p>Now, change back to the root directory of the project. Then, run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> run migrate</code></pre></div><p>This will create a new SQLite database <code class="language-text">db/db.sqlite3</code>, then using the migration you created earlier creates the <code class="language-text">users</code> table.</p><p>You can check this if you have an SQLite viewer. I use <a href="https://sqlitebrowser.org">DB Browser for SQLite</a>.</p><p>You'll see that the database has the users table with the columns you added in the <code class="language-text">up</code> function.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-26-at-8.04.21-PM.png" class="kg-image" alt="Knex.js Tutorial For Beginners" loading="lazy" width="880" height="396" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-26-at-8.04.21-PM.png 600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-26-at-8.04.21-PM.png 880w" sizes="(min-width: 720px) 720px"/></figure><h2 id="create-a-seed">Create a Seed</h2><p>A Seed file allows you to add data into your database without having to manually add them. This is helpful when filling the database with demo data to be able to easily test your website or server.</p><p>To create a seed file, run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">knex seed:make <span class="token function">users</span> --knexfile db/knexfile.js</code></pre></div><p>This will create the seed file <code class="language-text">users.js</code> inside <code class="language-text">db/seeds</code>. The <code class="language-text">knexfile</code> option specifies the location of <code class="language-text">knexfile.js</code>.</p><p>If you open <code class="language-text">db/seed/users.js</code>, you'll see the function <code class="language-text">seed</code>. This function first deletes all current users in the database then adds new ones.</p><p>Replace the content of the file with the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">exports<span class="token punctuation">.</span><span class="token function-variable function">seed</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">knex</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Deletes ALL existing entries</span> <span class="token keyword">return</span> <span class="token function">knex</span><span class="token punctuation">(</span><span class="token string">'users'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">del</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Inserts seed entries</span> <span class="token keyword">return</span> <span class="token function">knex</span><span class="token punctuation">(</span><span class="token string">'users'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token punctuation">{</span><span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Hettie Marshall'</span><span class="token punctuation">,</span> <span class="token literal-property property">email</span><span class="token operator">:</span> <span class="token string">'lantunde@acbo.va'</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Hester Owens'</span><span class="token punctuation">,</span> <span class="token literal-property property">email</span><span class="token operator">:</span> <span class="token string">'zo@girih.lv'</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Henry Jackson'</span><span class="token punctuation">,</span> <span class="token literal-property property">email</span><span class="token operator">:</span> <span class="token string">'bekamohi@owo.mt'</span><span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> </code></pre></div><p>Now this function inserts 3 users into the <code class="language-text">users</code> table.</p><p>Now, add the <code class="language-text">seed</code> command to <code class="language-text">package.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"seed"</span><span class="token operator">:</span> <span class="token string">"knex seed:run --knexfile db/knexfile.js"</span></code></pre></div><p>Then, run the command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> run seed</code></pre></div><p>This will add the 3 users to the database. You can use the SQLite viewer again to check it.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-26-at-8.08.42-PM.png" class="kg-image" alt="Knex.js Tutorial For Beginners" loading="lazy" width="884" height="362" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-26-at-8.08.42-PM.png 600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-26-at-8.08.42-PM.png 884w" sizes="(min-width: 720px) 720px"/></figure><h2 id="read-data-with-knexjs">Read Data with Knex.js</h2><p>In this section, you'll create a GET endpoint to retrieve users. You'll use Knex.js to retrieve the users.</p><p>In <code class="language-text">index.js</code> add the new route:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/user'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// TODO get users</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>To retrieve data from the database using Knex.js, you first use <code class="language-text">knex(<TABLE_NAME>)</code> to access the table, then use the method <code class="language-text">select</code> to specify which columns you want to retrieve.</p><p>Finally, to use the retrieved data you can either use a Promise or a callback.</p><p>Add the following inside the callback function for the newly created route:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">knex</span><span class="token punctuation">(</span><span class="token string">'users'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">select</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'id'</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'name'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">users</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span>users<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'An error occurred, please try again later.'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>This accesses the table <code class="language-text">users</code> with <code class="language-text">knex</code>, then selects <code class="language-text">id</code> and <code class="language-text">name</code>. Inside <code class="language-text">then</code>'s fulfillment handler returns a JSON response with the users array. <code class="language-text">catch</code> handles any errors that might occur.</p><p>Let's test it out! If you don't have the server running make sure to run it again:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>Then, send a GET request to <code class="language-text">localhost:3000/user</code>. You will receive an array of users.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-26-at-8.23.20-PM.png" class="kg-image" alt="Knex.js Tutorial For Beginners" loading="lazy" width="1082" height="542" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-26-at-8.23.20-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-26-at-8.23.20-PM.png 1000w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-26-at-8.23.20-PM.png 1082w" sizes="(min-width: 720px) 720px"/></figure><h2 id="insert-data-with-knexjs">Insert Data with Knex.js</h2><p>In this section, you'll learn how to insert data in the database using Knex.</p><p>Create a new POST route that allows us to add a new user:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">'/user'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// TODO insert user</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Inside the function, you need to first get the data from the body of the request. Then if it all looks good, you can use the <code class="language-text">insert</code> method on <code class="language-text">knex</code> to insert new data.</p><p>Add the following inside the callback function of the route:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> name <span class="token operator">=</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>name <span class="token operator">?</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>name <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">;</span> <span class="token keyword">const</span> email <span class="token operator">=</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>email <span class="token operator">?</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>email <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>name<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'Name is required'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">knex</span><span class="token punctuation">(</span><span class="token string">'users'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token punctuation">{</span>name<span class="token punctuation">,</span> email<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">id</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//get user by id</span> <span class="token function">knex</span><span class="token punctuation">(</span><span class="token string">'users'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">select</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'id'</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'name'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">where</span><span class="token punctuation">(</span><span class="token punctuation">{</span>id<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">user</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span>user<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'An error occurred, please try again later.'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This first get <code class="language-text">name</code> and <code class="language-text">email</code> from the body of the request. If <code class="language-text">name</code> isn't found then it returns an error.</p><p>If all is good, a new user will be inserted. Then, inside the fulfillment handler <code class="language-text">then</code>, you receive as a parameter the id of the newly added user. Use it to retrieve the user and return it.</p><p>Now, send a POST request to <code class="language-text">localhost:3000/user</code> and in the body add a <code class="language-text">name</code> and <code class="language-text">email</code> parameter. The new user will be inserted and returned in the request.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-26-at-9.10.05-PM.png" class="kg-image" alt="Knex.js Tutorial For Beginners" loading="lazy" width="2000" height="560" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-26-at-9.10.05-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-26-at-9.10.05-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-26-at-9.10.05-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-26-at-9.10.05-PM.png 2228w" sizes="(min-width: 720px) 720px"/></figure><h2 id="conclusion">Conclusion</h2><p>With Knex.js, you can easily prepare for different environments and setups. You can use the same methods and code to perform actions on the database and just change the configuration for the connection in one file when needed.</p><p>Make sure to read the <a href="https://knexjs.org">Knex.js documentation</a> to learn more about how to use it in your projects.</p>]]></content:encoded></item><item><title><![CDATA[On Edge Between SEO and Design]]></title><description><![CDATA[Though many US businesses have websites, they still ask, why is design important? Apart from a good impression it helps nurture leads. Learn more in this article.]]></description><link>https://blog.shahednasser.com/on-edge-between-seo-and-design/</link><guid isPermaLink="false">Ghost__Post__6176bca56e5b3510767b3d92</guid><category><![CDATA[SEO]]></category><category><![CDATA[Design]]></category><dc:creator><![CDATA[Tim Absalikov]]></dc:creator><pubDate>Mon, 25 Oct 2021 14:24:52 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/523d3e5f750b6a9a4817d5aeb5215efa/merakist-l5if0iQfV4c-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/523d3e5f750b6a9a4817d5aeb5215efa/merakist-l5if0iQfV4c-unsplash-2.jpg" alt="On Edge Between SEO and Design"/><p>Search engine optimization is critical to websites performance. However, many US businesses concentrate more on design than search engine optimization. SEO creates a less imperfect website than the competition; hence, a better chance of ranking higher in search engines than the competition.</p><p>Combining SEO and design is the best way to rank better on the search engine results page(SERPS). A poor <strong>bad graphic design squander the</strong> organic equity.</p><h2 id="importance-of-web-design-in-seo-website-navigation">Importance of Web Design in SEO website navigation</h2><p>You may wonder: <strong>why is design important</strong>? User experience is a critical factor in search engine ranking. Your website's design and how visitors interact with different aspects affect that website ranking in SERPs.</p><p>A navigation structure guides users through the brand experience. It affects significant metrics such as bounce rate, average page on time, conversion rate, and engagement rate. These factors can also increase revenue and profits.</p><p>Through <strong>clear navigation,</strong> search engine crawlers find and crawl the content.Besides, a navigation system helps the search engines to understand the most critical pages on your website. This helps shape page authority.</p><p>It's hard for web crawlers to locate important pages on incomplete and overcrowded navigation systems. Similarly, poor navigation systems dilute link equity.</p><p>Also, broken links result in 404-error, meaning the page is non-existent. Visitors cannot stay on such a page. So, design attention-grabbing 404 pages instead of using generic designs. Also, you can list essential web pages on the 404 pages.</p><p>Ideally, the design choice can alter how visitors view your website. Ensure that a navigation design fits well with the rest of the website design.</p><h2 id="tips-to-achieve-clear-navigation-on-your-site">Tips to Achieve Clear navigation on Your Site</h2><p>A website is insignificant if visitors cannot find the solution to their problem. So, the navigation design of your website must make sense not only to your internal team and your visitors. Build better relationships with your visitors and reduce bounce rates by creating an easy-to-use website.</p><p>The website navigation is like your visitor's roadmap. Typically, you are providing direction on where to go. How do you achieve clear<strong> navigation</strong>?</p><ul><li>Put your navigation menu at the top of the page, and it should lead in the right direction.</li><li>Make the menu very simple, i.e., limit the number of items. Include only top-level pages like About Us, Why Us, and Products/Services pages.</li><li>Use simple terminologies in the main menu, i.e., avoid technical jargons</li><li>Use Subpages/Sub-navigation to breakdown navigation choices. Use SEO</li><li>Add a search bar for visitors to quickly locate a page of interest</li><li>Ensure each page URL is clear, concise, and descriptive</li><li>The main menu must be accessible to smaller mobile devices</li></ul><p>However, a practical navigation menu that also supports SEO strategy comes with some tradeoffs. For instance, you may forego some creativity for user-friendliness and intuitiveness. For ways better navigate the a website, professional <a href="https://lastingtrend.com/services/seo-web-design/">website design service</a> can help you fix it.</p><h2 id="which-content-strategy-is-less-more-or-is-more-better">Which Content Strategy? is Less More, or is More Better?</h2><p>Less content grabs attention, but a longer message informs the reader.</p><h3 id="less-is-more">Less is More.</h3><p>The attention span for website users is about 7 seconds. When <strong>web pages take a long time to load</strong>, the bounce rate is higher.</p><p>Shorter is preferable when:</p><ul><li>Your target is the general public</li><li>Your audience is familiar with a service/product</li><li>Your service/product is straightforward</li></ul><p>So, focus on publishing high-quality and rich content, i.e., show industry expertise via your content. Google focuses more on ranking premium quality content.</p><p>500-word blog posts, 30-second video ads, and micro-content, e.g., tweets and status updates,perform well on smartphones.</p><p>Sadly, short content has a short life span. Therefore, you need to produce them constantly.</p><p>Shorter is beneficial in:</p><ul><li>Generating traffic</li><li>Increasing click-through rates</li><li>Generating qualified leads.</li><li>Previewing long-form content</li></ul><h3 id="long-form-content">Long-Form content</h3><p>Macro content works well when you break it into digestible form. Besides, intersperse it with images. Search engines prefer longer content. Why? People who know more about a subject say more, i.e., offer<strong>more knowledge</strong>. According to <a href="https://backlinko.com/content-study">BackLinko</a>, longer articles have more social media shares than shorter articles.</p><p>Use long-form content when dealing with unique, more expensive, and technical products/services. Such products/services require in-depth explanations. But the content must be authoritative, giving more scope and engaging.</p><h2 id="indexable-pages-appear-on-serps">Indexable Pages Appear on SERPs</h2><p>Sites not on a search engines index are not discoverable. Search engines use the index (database)as they contain all data that search engines find. Therefore, the data in the search engines index determines the value of different keywords and search terms.</p><p>The index includes URLs, content (texts, images, videos), and everything within the URL's HTML code. Search engine algorithms apply data and measure the frequency of different aspects under the various circumstance to index web pages.</p><p>Gathered information from web crawlers flows back to the search engines offering <strong>more knowledge </strong>about the index data. The evaluation is the analysis of the subject covered alongside an attempt to understand the content that best meets a particular user intent. When a user types your keyword or link, it will be indexed.</p><p>Therefore, <strong>indexable </strong>content will make your web page rank on search engines. Ensure that the content is available and up to date. If a web crawler encounters404 error pages, it may cease indexing your pages. Similarly, avoid orphan pages as they may interrupt bots from crawling your website. Note that these pages aren't connected with the rest of your website with internal links, and you can't access them through incoming links.</p><h2 id="optimize-product-and-website-images-for-better-ranking">Optimize Product and Website Images for Better Ranking</h2><p>Images are a bigger part of the <strong>design and visual communications</strong>. They add value and increase user engagement and website accessibility. Therefore, they can generate a lot of web traffic from image-based search engines such as Google.</p><p><a href="https://gs.statcounter.com/search-engine-market-share/desktop/worldwide">Over 85%</a>of all US web searches happen on Google. Therefore, optimizing your site photos and images is a way of capturing your visitor's attention. Here are a few ways to optimize the pictures to allow web crawlers to spot them:</p><ul><li>Scaling images - this improves page load speed. Size your images into proper width, height, and resolution quality. Too large images affect load times, while fuzzy images degrade website quality.</li><li>Use the proper format. JPEG and PNG are the major formats. PNG has better quality images, but files are larger. JPEG isn't top quality but allows you to adjust the quality level to find a good balance.</li><li>Create SEO-Friendly Alt Text. Alt tags describe the image content, and a browser uses them if it cannot render images correctly. With appropriate alt tags, your website can achieve better ranking – search engines associates keywords with images.</li><li>Image file names – name the files using words that describe them accurately and clearly, e.g., running shoes and not image 01.</li></ul><h2 id="conclusion">Conclusion</h2><p>The worlds of web design and SEO are merging closer each day. The various design-specific elements produce a positive impact on SEO for sites that use them.The idea is to have a well-balanced website. Such a site strikes a perfect balance between attraction, functionality, and SEO. If a web page doesn’t load properly, the <strong>website only shows text</strong>. Here, functionality is hampered. Visitors must always find the information they want, including visuals. So, make the information available and easy to find.A good user design influences longer visitor sessions, thus, lower bounce rates. It is aesthetically appealing, and general navigation across the website is much easier.</p>]]></content:encoded></item><item><title><![CDATA[How to Animate Components' Entrance and Exit in React]]></title><description><![CDATA[In this tutorial, we'll cover how to animate components' entrance and exit in React using React Transition Group.]]></description><link>https://blog.shahednasser.com/how-to-animate-components-entrance-and-exit-in-react/</link><guid isPermaLink="false">Ghost__Post__61705ebc6e5b3510767b39ab</guid><category><![CDATA[React]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 21 Oct 2021 10:26:43 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/68d609af4788e9d314c4a78cf0c7f662/sebastian-svenson-d2w-_1LJioQ-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/68d609af4788e9d314c4a78cf0c7f662/sebastian-svenson-d2w-_1LJioQ-unsplash.jpg" alt="How to Animate Components' Entrance and Exit in React"/><p>Say you have a list component in React where the user can add or remove items in the list. It would be nice to animate the items as they are being added or removed from the list.</p><p>In this tutorial, we'll cover how to animate components' entrance and exit in React using <a href="http://reactcommunity.org/react-transition-group/">React Transition Group</a>.</p><p>You can find the full code for this tutorial in <a href="https://github.com/shahednasser/react-transition-group-tutorial">this GitHub Repository</a>, and you can see a <a href="https://react-transition-group-tutorial.netlify.app">working demo</a>.</p><h2 id="what-is-react-transition-group">What is React Transition Group</h2><p>React Transition Group is a library that allows you to add animation on a component or multiple components' entrance and exit.</p><p>React Transition Group does NOT do the animation for you, that is it does not provide the animation. It facilitates adding the animation either through CSS classes or styles when a component enters or exits.</p><p>React Transition Group exposes the components that will allow you to easily do that. There are 4 components that it exposes: <a href="http://reactcommunity.org/react-transition-group/transition">Transition</a>, <a href="http://reactcommunity.org/react-transition-group/css-transition">CSSTransition</a>, <a href="http://reactcommunity.org/react-transition-group/switch-transition">SwitchTransition</a>, and <a href="http://reactcommunity.org/react-transition-group/transition-group">TransitionGroup</a>.</p><p>We'll go over different use cases when it comes to animating elements, and in each use case which component you should use and how you can use them.</p><h2 id="animating-a-single-element">Animating a Single Element</h2><p>The first use case we'll look at is animating a single element. Let's say we have an element that we want to animate every time it enters or exits.</p><p>There are 2 components we can use: <code class="language-text">Transition</code> and <code class="language-text">CSSTransition</code>. The recommended component is <code class="language-text">CSSTransition</code>, but we'll cover both.</p><h3 id="using-transition">Using Transition</h3><p>With the <code class="language-text">Transition</code> component, you can add CSS styling based on the different states. This component covers the states:</p><ol><li><code class="language-text">entering</code>: Before the element enters.</li><li><code class="language-text">entered</code>: Element has entered.</li><li><code class="language-text">exiting</code>: Before the element exits</li><li><code class="language-text">exited</code>: The element has exited.</li></ol><p>Generally, <code class="language-text">CSSTransition</code> is recommended to be used instead of <code class="language-text">Transition</code>. <code class="language-text">Transition</code> is provided as a platform-agnostic base component.</p><p>For this example, we'll have a button that will allow us to show or hide a picture of a cat. First, we need to create a state variable to store and indicate whether the image should be shown or not.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>transitionState<span class="token punctuation">,</span> setTransitionState<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span></code></pre></div><p>Then, We'll use the <code class="language-text">Transition</code> component to wrap the <code class="language-text">img</code> element. The <code class="language-text">Transition</code> component takes the prop <code class="language-text">in</code> which is a boolean variable that indicates whether the component should enter or not. We should pass the state variable to this prop.</p><p>Another required prop that <code class="language-text">Transition</code> accepts is <code class="language-text">timeout</code> which defines the duration of the animation.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Transition <span class="token keyword">in</span><span class="token operator">=</span><span class="token punctuation">{</span>transitionState<span class="token punctuation">}</span> timeout<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">300</span><span class="token punctuation">}</span> <span class="token operator">></span> <span class="token operator">...</span> <span class="token operator"><</span><span class="token operator">/</span>Transition</code></pre></div><p>Inside <code class="language-text">Transition</code>, a function is passed which receives the <code class="language-text">state</code> parameter. This parameter indicates the current state of the component, which will be one of the 4 states mentioned earlier.</p><p>Using that <code class="language-text">state</code> variable we can change the CSS styling of the component to animate it.</p><p>So, we need to create an object that holds the stylings we want to apply:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> transitions <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">entering</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">display</span><span class="token operator">:</span> <span class="token string">'block'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">entered</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">display</span><span class="token operator">:</span> <span class="token string">'block'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">exiting</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token literal-property property">display</span><span class="token operator">:</span> <span class="token string">'block'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">exited</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span> <span class="token literal-property property">display</span><span class="token operator">:</span> <span class="token string">'none'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div><p>Notice how we set the object keys or properties as the name of the states.</p><p>Then, in the child function of <code class="language-text">Transition</code>, we set the style based on the current state:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Transition <span class="token keyword">in</span><span class="token operator">=</span><span class="token punctuation">{</span>transitionState<span class="token punctuation">}</span> timeout<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">300</span><span class="token punctuation">}</span> <span class="token operator">></span> <span class="token punctuation">{</span><span class="token parameter">state</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>img src<span class="token operator">=</span><span class="token string">"https://cataas.com/cat"</span> alt<span class="token operator">=</span><span class="token string">"Cat"</span> style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">transition</span><span class="token operator">:</span> <span class="token string">'all .1s'</span><span class="token punctuation">,</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token literal-property property">display</span><span class="token operator">:</span> <span class="token string">'none'</span><span class="token punctuation">,</span> <span class="token operator">...</span>transitions<span class="token punctuation">[</span>state<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> className<span class="token operator">=</span><span class="token string">"mt-2"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Transition<span class="token operator">></span></code></pre></div><p>Notice how the function returns the <code class="language-text">img</code> element. Inside the <code class="language-text">style</code> prop of the <code class="language-text">img</code> element we first set the default styling, then we add the styling based on the state using this line:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator">...</span>transitions<span class="token punctuation">[</span>state<span class="token punctuation">]</span></code></pre></div><p>Now, everytime the state changes when the component enters or exits, the <code class="language-text">state</code> variable in the child function will change. So, the styling of the element will change based on the value of the <code class="language-text">state</code> variable, which will add animation to the element.</p><p>Also, the image we're using is from <a href="https://cataas.com/#/">Cat as a service</a>.</p><p>The only thing left is to add a button to toggle the state variable <code class="language-text">transitionState</code> to show and hide the image:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Button onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setTransitionState</span><span class="token punctuation">(</span><span class="token operator">!</span>transitionState<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{</span>transitionState <span class="token operator">?</span> <span class="token string">'Hide'</span> <span class="token operator">:</span> <span class="token string">'Show'</span><span class="token punctuation">}</span> Cat<span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span></code></pre></div><h3 id="using-csstransition">Using CSSTransition</h3><p>The recommended approach for this use case is using <code class="language-text">CSSTransition</code>. The <code class="language-text">CSSTransition</code> component allows you to add classes for each state, which gives you more freedom to add animation to your components.</p><p>To make the animation easier we'll use <a href="https://animate.style">Animate.css</a> which is a CSS animation library that provides us with many animations we can easily use.</p><p>To animate an element with <code class="language-text">CSSTransition</code>, you wrap it within the <code class="language-text">CSSTransition</code> component. Similar to <code class="language-text">Transition</code> <code class="language-text">CSSTransition</code> receives the <code class="language-text">in</code> prop which indicates whether the component should enter or exit. Also, it accepts the <code class="language-text">timeout</code> prop which determines the duration of the animation.</p><p>Unlike <code class="language-text">Transition</code>, <code class="language-text">CSSTransition</code> receives the prop <code class="language-text">classNames</code> which allows us to define the classes that should be added based on the different states.</p><p><code class="language-text">classNames</code> can be an object or a string. If a string is passed, the class will be used as a prefix for the different states. For example, if you pass to <code class="language-text">classNames</code> "fade", the class <code class="language-text">fade-enter</code> will be added to the component when it enters. When the component exits, the class <code class="language-text">fade-exit</code> is added. The same goes for the rest of the states.</p><p>If an object is passed as the value for <code class="language-text">classNames</code>, then the keys or properties should be the name of the state, and the value should be the class to apply for that state. For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">classNames<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">appear</span><span class="token operator">:</span> <span class="token string">'fade-in'</span><span class="token punctuation">,</span> <span class="token literal-property property">appearActive</span><span class="token operator">:</span> <span class="token string">'fade-in-active'</span><span class="token punctuation">,</span> <span class="token literal-property property">appearDone</span><span class="token operator">:</span> <span class="token string">'fade-in-appeared'</span><span class="token punctuation">,</span> <span class="token literal-property property">enter</span><span class="token operator">:</span> <span class="token string">'fade-in-enter'</span><span class="token punctuation">,</span> <span class="token literal-property property">enterActive</span><span class="token operator">:</span> <span class="token string">'fade-in-enter-active'</span><span class="token punctuation">,</span> <span class="token literal-property property">enterDone</span><span class="token operator">:</span> <span class="token string">'fade-in-done'</span><span class="token punctuation">,</span> <span class="token literal-property property">exit</span><span class="token operator">:</span> <span class="token string">'fade-out'</span><span class="token punctuation">,</span> <span class="token literal-property property">exitActive</span><span class="token operator">:</span> <span class="token string">'fade-out-active'</span><span class="token punctuation">,</span> <span class="token literal-property property">exitDone</span><span class="token operator">:</span> <span class="token string">'fade-out-active'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre></div><p>Notice that you don't need to add class names for all these states. This just gives you more freedom and flexibility over it. Generally, you should set the class that you want to apply when the element enters to <code class="language-text">enterActive</code>, and the class that you want to apply when the element exits to <code class="language-text">exitActive</code>. Basically, the <code class="language-text">active</code> phase of each state is when you should apply the animation.</p><p>So, back to our example, we want to animate an image of a cat as it is toggled by a button. First, we'll add 2 state variables:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>showCat<span class="token punctuation">,</span> setShowCat<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>imageClasses<span class="token punctuation">,</span> setImageClasses<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">"d-none"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p><code class="language-text">showCat</code> will be used for the <code class="language-text">in</code> prop to determine when the element should enter and exit. As for <code class="language-text">imageClasses</code>, we'll get to why we need it later on.</p><p>Next, we'll add the <code class="language-text">CSSTransition</code> component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>CSSTransition <span class="token keyword">in</span><span class="token operator">=</span><span class="token punctuation">{</span>showCat<span class="token punctuation">}</span> timeout<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">500</span><span class="token punctuation">}</span> classNames<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">enterActive</span><span class="token operator">:</span> <span class="token string">'animate__bounceIn'</span><span class="token punctuation">,</span> <span class="token literal-property property">exitActive</span><span class="token operator">:</span> <span class="token string">'animate__bounceOut'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> onEnter<span class="token operator">=</span><span class="token punctuation">{</span>showImage<span class="token punctuation">}</span> onEntered<span class="token operator">=</span><span class="token punctuation">{</span>removeOpacity<span class="token punctuation">}</span> onExited<span class="token operator">=</span><span class="token punctuation">{</span>hideImage<span class="token punctuation">}</span> className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">animate__animated my-4 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>imageClasses<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator">...</span> <span class="token operator"><</span><span class="token operator">/</span>CSSTransition<span class="token operator">></span></code></pre></div><p>Notice the following:</p><ol><li>On <code class="language-text">enterActive</code>, which is when the element should appear, we add the class <code class="language-text">animate__bounceIn</code>, and on <code class="language-text">exitActive</code>, which is when the element should exit, we add the class <code class="language-text">animate__bounceOut</code>. Both these classes are from the Animate.css library.</li><li>We have added a listener for <code class="language-text">onEnter</code>, which will be triggered when the element enters; a listener for <code class="language-text">onEntered</code>, which will be triggered when the element has finished entering; a listener for <code class="language-text">onExited</code> which will be triggered when the element has exited. We'll implement these listeners in a bit.</li><li>We have passed a <code class="language-text">className</code> prop that would add default classes to the child component.</li></ol><p>As you can see, we're using the state variable <code class="language-text">imageClasses</code> inside the string passed to <code class="language-text">className</code>. When using <code class="language-text">CSSTransition</code>, you'll assume that the exit state will be applied initially when the initial value passed to <code class="language-text">in</code> is false. That's actually not true. Initially, if the value of the <code class="language-text">in</code> prop is false, no classes are added.</p><p>As we don't want the image to be initially visible, we're using a state variable to add the Bootstrap class <code class="language-text">d-none</code> as we're using it in our project. This class will hide the element when added.</p><p>And this is why we added the event listeners. We'll change the value of <code class="language-text">imageClasses</code> based on each state:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">hideImage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setImageClasses</span><span class="token punctuation">(</span><span class="token string">"d-none"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">showImage</span><span class="token punctuation">(</span><span class="token parameter">node</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setImageClasses</span><span class="token punctuation">(</span><span class="token string">"d-block"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> node<span class="token punctuation">.</span>style<span class="token punctuation">.</span>opacity <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">removeOpacity</span> <span class="token punctuation">(</span><span class="token parameter">node</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> node<span class="token punctuation">.</span>style<span class="token punctuation">.</span>opacity <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Inside <code class="language-text">CSSTransition</code> we add the element we want to animate:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>CSSTransition <span class="token keyword">in</span><span class="token operator">=</span><span class="token punctuation">{</span>showCat<span class="token punctuation">}</span> timeout<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">500</span><span class="token punctuation">}</span> classNames<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">enterActive</span><span class="token operator">:</span> <span class="token string">'animate__bounceIn'</span><span class="token punctuation">,</span> <span class="token literal-property property">exitActive</span><span class="token operator">:</span> <span class="token string">'animate__bounceOut'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> onEnter<span class="token operator">=</span><span class="token punctuation">{</span>showImage<span class="token punctuation">}</span> onEntered<span class="token operator">=</span><span class="token punctuation">{</span>removeOpacity<span class="token punctuation">}</span> onExited<span class="token operator">=</span><span class="token punctuation">{</span>hideImage<span class="token punctuation">}</span> className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">animate__animated my-4 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>imageClasses<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>img src<span class="token operator">=</span><span class="token string">"https://cataas.com/cat"</span> alt<span class="token operator">=</span><span class="token string">"Cat"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>CSSTransition<span class="token operator">></span></code></pre></div><p>That's it! The only thing left is to add the button to toggle the <code class="language-text">showCat</code> state variable:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Button onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setShowCat</span><span class="token punctuation">(</span><span class="token operator">!</span>showCat<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{</span>showCat <span class="token operator">?</span> <span class="token string">'Hide'</span> <span class="token operator">:</span> <span class="token string">'Show'</span><span class="token punctuation">}</span> Cat<span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span></code></pre></div><p>Now, every time you click the button the classes will change based on the state.</p><h2 id="animate-a-group-of-element">Animate a Group of Element</h2><p>This applies to the first example mentioned in this article. Let's say you have a list and you want to animate whenever an element is added or removed from it. The elements will generally be dynamic, so you can't use <code class="language-text">CSSTransition</code> or <code class="language-text">Transition</code> on them one by one.</p><h3 id="using-transitiongroup">Using TransitionGroup</h3><p>The component <code class="language-text">TransitionGroup</code> wraps a list of <code class="language-text">CSSTransition</code> or <code class="language-text">Transition</code> components and manages their animation based on their states. In a use case where the list of elements to be added is dynamic, it's useful to use this component.</p><p>You pass <code class="language-text">CSSTransition</code> or <code class="language-text">Transition</code> components as children. There's no need to pass props to <code class="language-text">TransitionGroup</code>, as the configuration for the animation is done through the props passed to the children components.</p><p>In this example, we'll have an array of 4 elements in the beginning. Then, the user can add an item by clicking on a button or removing an item by clicking on the X icon.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-21-at-12.18.50-PM.png" class="kg-image" alt="How to Animate Components' Entrance and Exit in React" loading="lazy" width="2000" height="641" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-21-at-12.18.50-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-21-at-12.18.50-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-21-at-12.18.50-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-21-at-12.18.50-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>To make the implementation easier, we'll have an array of languages to add items from it randomly:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> defaultLanguages <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Java'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'JavaScript'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'PHP'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'CSS'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'C'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'C#'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'HTML'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Kotlin'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'TypeScript'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Swift'</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre></div><p>And we'll use a one-liner function from <a href="https://1loc.dev">1Loc</a> to get random elements from an array:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">randomItems</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">arr<span class="token punctuation">,</span> count</span><span class="token punctuation">)</span> <span class="token operator">=></span> arr<span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">p<span class="token punctuation">,</span> _<span class="token punctuation">,</span> __<span class="token punctuation">,</span> arr</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span>p<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator"><</span> count <span class="token operator">?</span> <span class="token punctuation">[</span>p<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> p<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>arr<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token operator">|</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">:</span> p<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre></div><p>Then, we'll define a state variable which will be the array of languages we'll show the user in a list:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>languages<span class="token punctuation">,</span> setLanguages<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token function">randomItems</span><span class="token punctuation">(</span>defaultLanguages<span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>counter<span class="token punctuation">,</span> setCounter<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>We also define a state variable <code class="language-text">counter</code> which we'll use to change the <code class="language-text">id</code> property from the <code class="language-text">defaultLanguages</code> array when adding a new item to the <code class="language-text">languages</code> array. This is just to ensure that the IDs are unique when we are choosing random items from the array.</p><p>Then, we render a <code class="language-text">TransitionGroup</code> component and inside it we loop over the <code class="language-text">languages</code> state variable and render a <code class="language-text">CSSTransition</code> component for that variable:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>TransitionGroup<span class="token operator">></span> <span class="token punctuation">{</span>languages<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>id<span class="token punctuation">,</span> name<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>CSSTransition key<span class="token operator">=</span><span class="token punctuation">{</span>id<span class="token punctuation">}</span> classNames<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">enterActive</span><span class="token operator">:</span> <span class="token string">'animate__animated animate__lightSpeedInLeft'</span><span class="token punctuation">,</span> <span class="token literal-property property">exitActive</span><span class="token operator">:</span> <span class="token string">'animate__animated animate__lightSpeedOutLeft'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> timeout<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">900</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>li className<span class="token operator">=</span><span class="token string">"p-3 border mb-3 shadow-sm rounded border-info d-flex justify-content-between"</span><span class="token operator">></span> <span class="token operator"><</span>span<span class="token operator">></span><span class="token punctuation">{</span>name<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator"><</span>CloseButton onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">removeLanguage</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>CloseButton<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>CSSTransition<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>TransitionGroup<span class="token operator">></span></code></pre></div><p>Notice that we're passing the class <code class="language-text">animate__animated animate__lightSpeedInLeft</code> for the state <code class="language-text">enterActive</code>. As mentioned in the previous section, this class we'll be added when the element enters. We're also passing the class <code class="language-text">animate__animated animate__lightSpeedOutLeft</code> for the state <code class="language-text">exitActive</code>. As mentioned in the previous section, this class we'll be added when the element exits. Also we're passing the <code class="language-text">timeout</code> prop with value <code class="language-text">900</code>.</p><p>Inside <code class="language-text">CSSTransition</code> we pass the element we want to animate which is an <code class="language-text">li</code> element. The element shows the name of the language and has a <code class="language-text">CloseButton</code> component which on click should remove the language from the list. Please note that the <code class="language-text">CloseButton</code> comes from the <a href="https://react-bootstrap.github.io">React Bootstrap</a> which we're using just for styling purposes.</p><p>As you can see <code class="language-text">TransitionGroup</code> is only used as a wrapper to these elements.</p><p>We also need to add a button to add languages:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Button onClick<span class="token operator">=</span><span class="token punctuation">{</span>addLanguage<span class="token punctuation">}</span><span class="token operator">></span>Add<span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span></code></pre></div><p>What's left is to implement the event listeners <code class="language-text">addLanguage</code> and <code class="language-text">removeLanguage</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">addLanguage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> newLanguages <span class="token operator">=</span> languages<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> newItem <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">assign</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token function">randomItems</span><span class="token punctuation">(</span>defaultLanguages<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> newItem<span class="token punctuation">.</span>id <span class="token operator">=</span> counter<span class="token punctuation">;</span> newLanguages<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>newItem<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setLanguages</span><span class="token punctuation">(</span>newLanguages<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setCounter</span><span class="token punctuation">(</span>counter <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">removeLanguage</span> <span class="token punctuation">(</span><span class="token parameter">id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> newLanguages <span class="token operator">=</span> languages<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> ind <span class="token operator">=</span> newLanguages<span class="token punctuation">.</span><span class="token function">findIndex</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">language</span><span class="token punctuation">)</span> <span class="token operator">=></span> language<span class="token punctuation">.</span>id <span class="token operator">===</span> id<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>ind <span class="token operator">!==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> newLanguages<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span>ind<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setLanguages</span><span class="token punctuation">(</span>newLanguages<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>The <code class="language-text">addLanguage</code> listener picks a random item from the array. We use <code class="language-text">Object.assign</code> to clone the item from the array instead of getting the item by reference. We then change the <code class="language-text">id</code> to make sure it's unique.</p><p>In the <code class="language-text">removeLanguage</code> listener we just find the index of the language in the array and remove it.</p><p>That's all! If you try it out, items that are added by clicking on the "Add" button will be animated as they enter. Items will also be animated when they exit by clicking on the X icon.</p><h2 id="applying-animation-with-a-switch">Applying Animation With a Switch</h2><p>The last case we'll cover is animating something based on its change of state. Let's say we have a button that would toggle between two states, and these two states would require a change in the appearance of another element. For this case, we can use the <code class="language-text">SwitchTransition</code> component.</p><p>The <code class="language-text">SwitchTransition</code> wraps a <code class="language-text">CSSTransition</code> or <code class="language-text">Transition</code> element. It accepts one prop <code class="language-text">mode</code> which can be of two values: <code class="language-text">out-in</code> or <code class="language-text">in-out</code>, with <code class="language-text">out-in</code> being the default. When choosing <code class="language-text">out-in</code>, it means that the old state exits first then the new state enters. When choosing <code class="language-text">in-out</code> it's the opposite; the new state enters then the old state exits.</p><p>When the state of the component changes, the component exits and a new component with the new state enters.</p><p>In this example, we'll have an <a href="https://react-bootstrap.github.io/components/alerts">Alert</a>, which is a component exposed by React Bootstrap. We'll have a state that will toggle the <code class="language-text">variant</code>, which is the background color and the theme of the Alert component, between <code class="language-text">danger</code> and <code class="language-text">success</code>. We'll also change the text of the Alert component based on the variant.</p><p>First, we'll define the state variable to toggle the state of the Alert component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>isDanger<span class="token punctuation">,</span> setIsDanger<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Then, we'll render the <code class="language-text">SwitchTransition</code> component which will take as a child a <code class="language-text">CSSTransition</code> component to manage the animation of the <code class="language-text">Alert</code> component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>SwitchTransition mode<span class="token operator">=</span><span class="token string">"out-in"</span><span class="token operator">></span> <span class="token operator"><</span>CSSTransition key<span class="token operator">=</span><span class="token punctuation">{</span>isDanger<span class="token punctuation">}</span> classNames<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">enterActive</span><span class="token operator">:</span> <span class="token string">'animate__animated animate__flipInX'</span><span class="token punctuation">,</span> <span class="token literal-property property">exitActive</span><span class="token operator">:</span> <span class="token string">'animate__animated animate__flipOutX'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> timeout<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">500</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Alert variant<span class="token operator">=</span><span class="token punctuation">{</span>isDanger <span class="token operator">?</span> <span class="token string">'danger'</span> <span class="token operator">:</span> <span class="token string">'success'</span><span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{</span>isDanger <span class="token operator">?</span> <span class="token string">"You're in danger"</span> <span class="token operator">:</span> <span class="token string">"Danger cleared"</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>Alert<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>CSSTransition<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>SwitchTransition<span class="token operator">></span></code></pre></div><p>As you can see we pass to <code class="language-text">SwitchTransition</code> the mode <code class="language-text">out-in</code>, but this is the default mode so it's optional to pass.</p><p>For <code class="language-text">CSSTransition</code> we pass it the prop <code class="language-text">key</code> which will be used to enter and exit elements based on the state. When the state variable <code class="language-text">isDanger</code> changes, the component will be removed and a new one with the new value will be added. This <code class="language-text">key</code> prop behaves exactly as it would when you render items from an array using <code class="language-text">map</code>.</p><p>For the <code class="language-text">enterActive</code> animation state, we add the class <code class="language-text">animate__animated animate__flipInX</code>. For the <code class="language-text">exitActive</code> animation sate, we add the class <code class="language-text">animate__animated animate__flipOutX</code>.</p><p>As for the child of <code class="language-text">CSSTransition</code> we pass the <code class="language-text">Alert</code> component, which sets the <code class="language-text">variant</code> and text based on the value of <code class="language-text">isDanger</code>.</p><p>Finally, we'll render a button to toggle the value of <code class="language-text">isDanger</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Button onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setIsDanger</span><span class="token punctuation">(</span><span class="token operator">!</span>isDanger<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token punctuation">{</span>isDanger <span class="token operator">?</span> <span class="token string">'Clear Danger'</span> <span class="token operator">:</span> <span class="token string">'Bring Danger'</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span></code></pre></div><p>If you try it now, you'll see that when you click the button the Alert will exit and the new one will enter. This is because of the mode <code class="language-text">out-in</code>.</p><p>If you try to change the mode to <code class="language-text">in-out</code>, you'll see that when you click the button a new Alert will enter and then the old one will exit.</p><h2 id="conclusion">Conclusion</h2><p>Adding animation to components provides a nice user experience and add a flair to your website.</p><p>In this tutorial, we learned how to use React Transition Group to animate a component's enterance or exit. Remember, this library does not add the animation for you. This library exposes components that will allow you to add the animation yourself.</p>]]></content:encoded></item><item><title><![CDATA[10 Awesome Web Development Resources You Might Not Know]]></title><description><![CDATA[In this article, I'll focus on resources related to web development that I personally found to be helpful, cool, or unique]]></description><link>https://blog.shahednasser.com/10-awesome-web-development-resources-you-might-not-know/</link><guid isPermaLink="false">Ghost__Post__616af8d07a819fa97764d33f</guid><category><![CDATA[Tips]]></category><category><![CDATA[Beginners]]></category><category><![CDATA[CSS]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 18 Oct 2021 14:14:41 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/26c92c0c80eb0123ddf6a7bd8b60e70c/arnel-hasanovic-MNd-Rka1o0Q-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/26c92c0c80eb0123ddf6a7bd8b60e70c/arnel-hasanovic-MNd-Rka1o0Q-unsplash-2.jpg" alt="10 Awesome Web Development Resources You Might Not Know"/><p>Last year, I created the repository <a href="https://github.com/shahednasser/awesome-resources">awesome-resources</a> which aimed to combine helpful resources about many topics in one place. All these resources are added by fellow contributors who have personally found these resources helpful for them.</p><p>Some of these resources can be necessary basic knowledge including the documentation of a framework or courses for a programming language.</p><p>On the other hand, some resources are not ones that everyone is familiar with. I personally didn't know about a lot of them and found them cool when reviewing pull requests.</p><p>Although this repository has resources related to almost every topic related to technology in particular, in this article I'll focus on resources related to web development that I personally found to be helpful, cool, or unique.</p><h2 id="css">CSS</h2><h3 id="style-stage-from-modern-css-solutions"><a href="https://stylestage.dev">Style Stage from Modern CSS Solutions</a></h3><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-16-at-7.11.49-PM.png" class="kg-image" alt="10 Awesome Web Development Resources You Might Not Know" loading="lazy" width="2000" height="1126" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-16-at-7.11.49-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-16-at-7.11.49-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-16-at-7.11.49-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-16-at-7.11.49-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>At first, I was confused about what this website was for, but when I went through it I loved the idea. Basically, this website shows you the exact same page in different stylesheets created by contributors. You can go view the <a href="https://stylestage.dev/styles/">list of styles</a> and pick one of them. You'll see unique different ways of designing the same page, and you can view the stylesheet to learn how it was done.</p><h3 id="grid-and-flex-cheat-sheets-by-chris-malven"><a href="https://grid.malven.co">Grid</a> and <a href="https://flexbox.malven.co">Flex</a> Cheat Sheets by Chris Malven</h3><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-16-at-7.17.17-PM.png" class="kg-image" alt="10 Awesome Web Development Resources You Might Not Know" loading="lazy" width="2000" height="911" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-16-at-7.17.17-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-16-at-7.17.17-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-16-at-7.17.17-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-16-at-7.17.17-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>We've seen many cheat sheets before, so there's nothing unique about a cheat sheet. However, this one I really liked because it had a simple visual explanation, and it's simple and to the point. I think most cheat sheets end up being too condensed as they try to put too much information in one place. This one is very easy to read and find what you need.</p><h3 id="glassmorphism-css-generator"><a href="https://ui.glass/generator/">Glassmorphism CSS Generator</a></h3><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-5.10.44-PM-1.png" class="kg-image" alt="10 Awesome Web Development Resources You Might Not Know" loading="lazy" width="2000" height="1211" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-17-at-5.10.44-PM-1.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-17-at-5.10.44-PM-1.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-17-at-5.10.44-PM-1.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-17-at-5.10.44-PM-1.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>This CSS Generator helps you create elements with a glass effect. You can select the type of background you want to use for the element, for example, an image. Then, you can specify details related to the color, opacity, and more.</p><p>Once you like the design, you can copy the CSS and HTML and use them on your website.</p><h2 id="javascript">JavaScript</h2><h3 id="coderslangjs"><a href="https://js.coderslang.com/">CoderslangJS</a></h3><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-4.35.03-PM.png" class="kg-image" alt="10 Awesome Web Development Resources You Might Not Know" loading="lazy" width="1614" height="1640" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-17-at-4.35.03-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-17-at-4.35.03-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-17-at-4.35.03-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-4.35.03-PM.png 1614w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://js.coderslang.com/">CoderlangJS</a> is another JavaScript course to learn JavaScript as a beginner. However, it does so in the form of a game with a storyline. It helps make the learning fun, especially for beginners.</p><p>It also doesn't just focus on the basics, it also focuses on more advanced topics like developing the backend with Node.js, deploying it with Docker, and more.</p><h3 id="javascript-30"><a href="https://javascript30.com">JavaScript 30</a></h3><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-4.38.04-PM.png" class="kg-image" alt="10 Awesome Web Development Resources You Might Not Know" loading="lazy" width="2000" height="990" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-17-at-4.38.04-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-17-at-4.38.04-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-17-at-4.38.04-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-4.38.04-PM.png 2166w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://javascript30.com">JavaScript 30</a> helps you learn Vanilla JavaScript by building components and projects without any libraries, frameworks, or any tool that might help you build it. Basically, you have to build everything from scratch. If you're looking to practice JavaScript and become advanced in it, this is a great way to start.</p><h3 id="favorite-javascript-utilities-in-single-line-of-code1loc"><a href="https://1loc.dev">Favorite JavaScript Utilities in Single Line of Code - 1LOC</a></h3><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-4.40.57-PM.png" class="kg-image" alt="10 Awesome Web Development Resources You Might Not Know" loading="lazy" width="2000" height="954" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-17-at-4.40.57-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-17-at-4.40.57-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-17-at-4.40.57-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-4.40.57-PM.png 2180w" sizes="(min-width: 720px) 720px"/></figure><p>This resource gives you utility functions in both JavaScript and TypeScript in one line. It includes utilities for Arrays, Date Time, DOM, and more. You are very likely to use these utilities in your project, so it's a nice resource to have bookmarked for when you need them.</p><h3 id="jsorg"><a href="https://js.org">JS.ORG</a></h3><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-4.43.54-PM.png" class="kg-image" alt="10 Awesome Web Development Resources You Might Not Know" loading="lazy" width="1810" height="1028" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-17-at-4.43.54-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-17-at-4.43.54-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-17-at-4.43.54-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-4.43.54-PM.png 1810w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://js.org">JS.ORG</a> provides repositories that are clearly related to JavaScript with a js.org subdomain. For example, foo.js.org. As there has been a lot of demand for subdomains, now JS.ORG is making sure to limit the subdomains they provide to those of clear relation to JavaScript.</p><p>So, if your repository is related to JavaScript, you can follow the steps on their website to get a free subdomain for your project.</p><h3 id="reactjs-cheat-sheet-by-devhintsio"><a href="https://devhints.io/react">React.js Cheat Sheet by devhints.io</a></h3><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-4.55.07-PM.png" class="kg-image" alt="10 Awesome Web Development Resources You Might Not Know" loading="lazy" width="2000" height="1299" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-17-at-4.55.07-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-17-at-4.55.07-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-17-at-4.55.07-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-17-at-4.55.07-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>This cheat sheet is specifically for <a href="https://reactjs.org">React</a> created by <a href="https://devhints.io">devhints.io</a>. It's a simple and to-the-point cheat sheet that is easily readable. It has information on components, lifecycle, hooks, and more.</p><h2 id="other">Other</h2><h3 id="web-accessibility-evaluation-tools-list"><a href="https://www.w3.org/WAI/ER/tools/">Web Accessibility Evaluation Tools List</a></h3><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-5.00.50-PM.png" class="kg-image" alt="10 Awesome Web Development Resources You Might Not Know" loading="lazy" width="2000" height="1125" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-17-at-5.00.50-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-17-at-5.00.50-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-17-at-5.00.50-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-17-at-5.00.50-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>This resource by W3C gives you tools that allow you to check your pages and make sure they properly provide accessibility for all people regardless of their disabilities. You can find tools like <a href="https://www.webaccessibility.com">WebAccessibility.com</a> and <a href="https://color.a11y.com/?wc3">Color Contrast Accessibility Validator</a>.</p><h3 id="404-illustrations"><a href="https://error404.fun">404 Illustrations</a></h3><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-5.08.00-PM.png" class="kg-image" alt="10 Awesome Web Development Resources You Might Not Know" loading="lazy" width="2000" height="1288" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-17-at-5.08.00-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-17-at-5.08.00-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-17-at-5.08.00-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-5.08.00-PM.png 2370w" sizes="(min-width: 720px) 720px"/></figure><p>This project provides you with free 404 illustrations you can use on your websites to make the 404 page more creative. The illustrations are available in PNG and SVG. You can also see an example of how to use these illustrations for inspiration.</p><h2 id="bonus">Bonus</h2><p>This section includes resources that I found helpful but are not necessarily related to Web Development in particular.</p><h3 id="list-of-badges-in-markdown"><a href="https://naereen.github.io/badges/">List of Badges, in Markdown </a></h3><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-5.04.12-PM.png" class="kg-image" alt="10 Awesome Web Development Resources You Might Not Know" loading="lazy" width="1502" height="1570" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-17-at-5.04.12-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-17-at-5.04.12-PM.png 1000w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-5.04.12-PM.png 1502w" sizes="(min-width: 720px) 720px"/></figure><p>This website and GitHub repository give you badges you can use in Markdown files. This is especially helpful for repository maintainers. You can find badges related to the status of the project, the version it supports, data related to the maintainer or contributors, and more.</p><h3 id="git-purr-git-commands-explained-with-cats"><a href="https://girliemac.com/blog/2017/12/26/git-purr/">GIT PURR! Git Commands Explained with Cats!</a></h3><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-5.18.29-PM.png" class="kg-image" alt="10 Awesome Web Development Resources You Might Not Know" loading="lazy" width="1500" height="1252" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-17-at-5.18.29-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-17-at-5.18.29-PM.png 1000w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-5.18.29-PM.png 1500w" sizes="(min-width: 720px) 720px"/></figure><p>I might be biased since I'm a cat lover, but when I saw this one I loved it. Not only is it an easy way for beginners to grasp Git commands with these drawings and doodles, but they're also super cute.</p><h3 id="machine-learning-roadmap-2020"><a href="https://whimsical.com/machine-learning-roadmap-2020-CA7f3ykvXpnJ9Az32vYXva">Machine Learning Roadmap 2020</a></h3><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-17-at-5.20.32-PM.png" class="kg-image" alt="10 Awesome Web Development Resources You Might Not Know" loading="lazy" width="2000" height="611" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-17-at-5.20.32-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-17-at-5.20.32-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-17-at-5.20.32-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-17-at-5.20.32-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>The reason I like this roadmap is that it's interactive with notes on how to get started with each roadmap item. I think we're always used to roadmaps related to how to start learning something with images. I personally find interactive resources are a better way to understand and learn something.</p><h2 id="conclusion">Conclusion</h2><p>Through creating the <a href="https://github.com/shahednasser/awesome-resources">awsome-resources</a> repository, I was able to learn about many resources that I personally didn't know existed. I think this is also one of the benefits of giving back to the community and contributing to open source projects.</p><p>This list is just a small list of the resources found in <a href="https://github.com/shahednasser/awesome-resources">the repository</a>. I encourage you to check it out and see other resources added by contributors that might be useful to you or others you might know. </p>]]></content:encoded></item><item><title><![CDATA[14 CSS Libraries You Should Check Out]]></title><description><![CDATA[In this article, we'll look at some CSS libraries that can be helpful and provide nice or unique styling.]]></description><link>https://blog.shahednasser.com/14-css-libraries-you-should-check-out/</link><guid isPermaLink="false">Ghost__Post__616598ad3eea8f060129b49c</guid><category><![CDATA[CSS]]></category><category><![CDATA[Beginners]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 14 Oct 2021 10:44:08 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/84445aeea8c20b746134746a7bbea7bf/kobu-agency-ipARHaxETRk-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/84445aeea8c20b746134746a7bbea7bf/kobu-agency-ipARHaxETRk-unsplash-2.jpg" alt="14 CSS Libraries You Should Check Out"/><p>CSS libraries can make your web development easier, as they pack in good styles into one library that you can just use in your projects without extra work from your side.</p><p>There are many CSS libraries out there, each providing its own helpful styling for your projects. In this article, we'll look at some of these libraries that provide nice or unique styling.</p><h2 id="nescss"><a href="https://nostalgic-css.github.io/NES.css/">NES.css</a></h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-12-at-5.20.14-PM.png" class="kg-image" alt="14 CSS Libraries You Should Check Out" loading="lazy" width="2000" height="1257" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-12-at-5.20.14-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-12-at-5.20.14-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-12-at-5.20.14-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-12-at-5.20.14-PM.png 2170w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://nostalgic-css.github.io/NES.css/">NES.css</a> is a library that falls under the unique category. It provides 8-bit styling for common UI elements. If you're developing a web game, or just want to give an 8-bit look to your website, this library is perfect for you.</p><h2 id="animatecss"><a href="https://animate.style">Animate.css</a></h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-12-at-5.22.46-PM.png" class="kg-image" alt="14 CSS Libraries You Should Check Out" loading="lazy" width="2000" height="1128" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-12-at-5.22.46-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-12-at-5.22.46-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-12-at-5.22.46-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-12-at-5.22.46-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://animate.style">Animate.css</a> is a library I have used in most of my projects. It provides you with a nice set of animation classes, and utilities to easily control these animations. It makes animation in CSS extremely easy to add to your projects, especially if you're a beginner.</p><h2 id="watercss"><a href="https://watercss.kognise.dev">Water.css</a></h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-12-at-5.33.55-PM.png" class="kg-image" alt="14 CSS Libraries You Should Check Out" loading="lazy" width="1972" height="1558" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-12-at-5.33.55-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-12-at-5.33.55-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-12-at-5.33.55-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-12-at-5.33.55-PM.png 1972w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://watercss.kognise.dev">Water.css</a> is a lightweight and responsive library that gives your website a simple styling. You don't need to add any specific CSS classes, it just adds the styling based on your HTML markup. This library also has a Bookmarklet that you can use on any website that doesn't have styling to add some nice styling to it.</p><h2 id="spectrum-css"><a href="https://opensource.adobe.com/spectrum-css/index.html">Spectrum CSS</a></h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-12-at-5.49.15-PM.png" class="kg-image" alt="14 CSS Libraries You Should Check Out" loading="lazy" width="2000" height="1120" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-12-at-5.49.15-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-12-at-5.49.15-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-12-at-5.49.15-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-12-at-5.49.15-PM.png 2228w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://opensource.adobe.com/spectrum-css/index.html">Spectrum CSS</a> is an open-source library created by Adobe. It includes a lot of nicely styled-components including Action Bars, Accordions, Cards, Ratings, and more. The styling is based on Adobe's design system.</p><h2 id="box-shadowscss"><a href="https://madeas.github.io/box-shadows/">Box-shadows.css</a></h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-12-at-5.51.57-PM.png" class="kg-image" alt="14 CSS Libraries You Should Check Out" loading="lazy" width="2000" height="1198" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-12-at-5.51.57-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-12-at-5.51.57-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-12-at-5.51.57-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-12-at-5.51.57-PM.png 2110w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://madeas.github.io/box-shadows/">Box-shadows.css</a> is a library solely focused on adding box-shadows to elements. It provides different utility classes for different shades, intensities, or types of box shadows.</p><h2 id="sbuttons"><a href="https://github.com/sButtons/sbuttons">sButtons</a></h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-12-at-5.55.01-PM.png" class="kg-image" alt="14 CSS Libraries You Should Check Out" loading="lazy" width="2000" height="854" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-12-at-5.55.01-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-12-at-5.55.01-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-12-at-5.55.01-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-12-at-5.55.01-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://github.com/sButtons/sbuttons">sButtons</a> is a library I personally developed with the help of many open-source contributors. This library provides you with many styled buttons of different types, including animated buttons, icon buttons, social login buttons, and more.</p><h2 id="hintcss"><a href="https://kushagra.dev/lab/hint/">Hint.css</a></h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-12-at-5.58.16-PM.png" class="kg-image" alt="14 CSS Libraries You Should Check Out" loading="lazy" width="2000" height="879" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-12-at-5.58.16-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-12-at-5.58.16-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-12-at-5.58.16-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-12-at-5.58.16-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://kushagra.dev/lab/hint/">Hint.css</a> is a library that you can use to add tooltips to any element. It's done with only pure CSS and it doesn't use any JavaScript. It's very small and easy to use in any of your projects.</p><h2 id="css-icons"><a href="https://css.gg">CSS Icons</a></h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-12-at-6.01.04-PM.png" class="kg-image" alt="14 CSS Libraries You Should Check Out" loading="lazy" width="2000" height="742" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-12-at-6.01.04-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-12-at-6.01.04-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-12-at-6.01.04-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-12-at-6.01.04-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://css.gg">CSS Icons</a> is a library that has 700+ icons in CSS, SVG, JSON, and more. You can add it to any of your projects regardless of what they are and it can be a very useful library.</p><h2 id="hamburgers"><a href="https://jonsuh.com/hamburgers/">Hamburgers</a></h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-14-at-12.41.37-PM.png" class="kg-image" alt="14 CSS Libraries You Should Check Out" loading="lazy" width="2000" height="831" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-14-at-12.41.37-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-14-at-12.41.37-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-14-at-12.41.37-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-14-at-12.41.37-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://jonsuh.com/hamburgers/">Hamburgers</a> is a CSS library that provides you with different styles of Hamburger buttons. You can use different icons or transitions and animations. Using this library you can easily add a nice-looking Hamburger button.</p><h2 id="ballooncss"><a href="https://kazzkiq.github.io/balloon.css/">Balloon.css</a></h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-14-at-12.48.21-PM.png" class="kg-image" alt="14 CSS Libraries You Should Check Out" loading="lazy" width="2000" height="1294" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-14-at-12.48.21-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-14-at-12.48.21-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-14-at-12.48.21-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-14-at-12.48.21-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://kazzkiq.github.io/balloon.css/">Balloon.css</a> is another pure CSS tooltip library. Using data attributes, you'll be able to add a tooltip to elements of any length or position, and you can add some CSS classes too to change the color of the tooltip.</p><h2 id="chartscss"><a href="https://chartscss.org">Charts.css</a> </h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-14-at-12.51.45-PM.png" class="kg-image" alt="14 CSS Libraries You Should Check Out" loading="lazy" width="1762" height="930" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-14-at-12.51.45-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-14-at-12.51.45-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-14-at-12.51.45-PM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-14-at-12.51.45-PM.png 1762w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://chartscss.org">Charts.css</a> is a library that allows you to visualize data in different types of charts using CSS. The library includes bar charts, line charts, column charts, and more. It can be done with their CSS classes and simple table HTML markups.</p><h2 id="csshake"><a href="https://elrumordelaluz.github.io/csshake/">CSShake</a></h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-14-at-12.54.56-PM.png" class="kg-image" alt="14 CSS Libraries You Should Check Out" loading="lazy" width="2000" height="1140" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-14-at-12.54.56-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-14-at-12.54.56-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-14-at-12.54.56-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-14-at-12.54.56-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://elrumordelaluz.github.io/csshake/">CSShake</a> is a CSS library that provides classes that simply allow you to shake any element in the DOM. They have classes related to intensity, direction, type, and more.</p><h2 id="flag-icons"><a href="https://flagicons.lipis.dev">flag-icons</a></h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-14-at-1.07.07-PM.png" class="kg-image" alt="14 CSS Libraries You Should Check Out" loading="lazy" width="2000" height="967" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-14-at-1.07.07-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-14-at-1.07.07-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-14-at-1.07.07-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-14-at-1.07.07-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p><a href="https://flagicons.lipis.dev">flag-icons</a> is a CSS library that gives you CSS classes to show flags of countries from around the world. This can save you time from finding flags to use in your website, and the flags are SVG.</p><h2 id="patterncss"><a href="https://bansal.io/pattern-css#separator">pattern.css</a></h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-14-at-1.35.47-PM.png" class="kg-image" alt="14 CSS Libraries You Should Check Out" loading="lazy" width="2000" height="1135" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-14-at-1.35.47-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-14-at-1.35.47-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-14-at-1.35.47-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-14-at-1.35.47-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>With <a href="https://bansal.io/pattern-css#separator">pattern.css</a> you can fill the background of the page, separator, text, and image with different pattern styles using only CSS classes provided by the library.</p><h2 id="conclusion">Conclusion</h2><p>CSS libraries can help you do more with less time. It saves you time and makes your website look nicer.</p><p>The ones mentioned in this article are just some of the helpful ones that I present to you in the hopes that they help you in your upcoming projects.</p>]]></content:encoded></item><item><title><![CDATA[Medusa: Create A Fast and Highly Customizable E-Commerce Store]]></title><description><![CDATA[In this article, we'll briefly take a look at Medusa's structure, its pros, and its cons.]]></description><link>https://blog.shahednasser.com/medusa-create-fast-and-highly-customizable-ecommerce-store/</link><guid isPermaLink="false">Ghost__Post__6161d15b3eea8f060129b2fc</guid><category><![CDATA[Reviews]]></category><category><![CDATA[eCommerce]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 11 Oct 2021 16:00:38 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/b8bc41e18ef83364e45ba3fb6a77ad91/Fast-and-Highly-Customizable-E-commerce-Stores.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/b8bc41e18ef83364e45ba3fb6a77ad91/Fast-and-Highly-Customizable-E-commerce-Stores.png" alt="Medusa: Create A Fast and Highly Customizable E-Commerce Store"/><p>E-commerce platforms and frameworks are usually built on a complex architecture to provide you with the best features as a developer and as a business owner. </p><p>Although this is good as they pack all useful features in one framework in the hopes no additional work needs to be done to launch a store, this can result in some issues. The store can be slow which would require a set of external tools to make it faster and in some cases big hosting plans to ensure the customers get the best experience.</p><p>In addition to that, customizing an e-commerce store to fit your or your client's needs using some platforms can be hard due to their tightly bound or complicated architecture.</p><p>This is where <a href="https://www.medusajs.com/">Medusa</a> comes in. Medusa is an open-source headless commerce platform that aims to simplify how e-commerce platforms are built and provide you with the highest level of customization you can attain to build the e-commerce store you have in mind.</p><p>In this article, we'll briefly take a look at Medusa's structure and what it provides, then we'll see what are some of its strong points and what are some of its cons that you should keep in mind before choosing Medusa.</p><h2 id="medusas-architecture">Medusa's Architecture </h2><p>Medusa as a full e-commerce system is split into 3 parts or 3 building blocks.</p><p>The core of Medusa is its <a href="https://github.com/medusajs/medusa/">backend</a>. The backend exposes a REST API and connects directly to the database. The backend acts as the headless commerce, accessing and managing the store's data. The backend is built with Node.js and express. By default and for development purposes it provides support for SQLite for the database, however, it also provides support for PostgreSQL and Redis.</p><p>Next comes the storefront. Medusa provides 2 storefronts that you can use, one built with <a href="https://github.com/medusajs/nextjs-starter-medusa">Next.js</a> and another with <a href="https://github.com/medusajs/gatsby-starter-medusa">Gatsby.js</a>. The storefront connects to the backend and provides a slick design and a fast experience for your users.</p><p>The last building block is the <a href="https://github.com/medusajs/admin">admin dashboard</a>. The admin dashboard connects to the backend and allows you to easily manage products, orders, customers, and settings.</p><p>The only building block required to use Medusa is the backend. With the backend, you are able to customize your storefront as you see fit. Although Medusa provides a storefront that you can use, you are not obligated to use it and can create your own. The same goes for the admin dashboard.</p><h2 id="e-commerce-features">E-Commerce Features</h2><p>In this section, we'll cover some of the e-commerce features that Medusa provides. These are the features that you should expect when you create a store with Medusa.</p><h3 id="product-variants">Product Variants</h3><p>In Medusa, you can easily add product variants like Size. You can also add multiple prices for different currencies, manage the inventory of each variant, and more.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-10-at-12.55.08-AM.png" class="kg-image" alt="Medusa: Create A Fast and Highly Customizable E-Commerce Store" loading="lazy" width="2000" height="743" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-10-at-12.55.08-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-10-at-12.55.08-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-10-at-12.55.08-AM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-10-at-12.55.08-AM.png 2078w" sizes="(min-width: 720px) 720px"/></figure><h3 id="discounts">Discounts</h3><p>You can add discounts or offer free shipping based on region. You can apply the discount as a percentage or as a fixed amount.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-10-at-12.56.30-AM.png" class="kg-image" alt="Medusa: Create A Fast and Highly Customizable E-Commerce Store" loading="lazy" width="1446" height="1568" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-10-at-12.56.30-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-10-at-12.56.30-AM.png 1000w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-10-at-12.56.30-AM.png 1446w" sizes="(min-width: 720px) 720px"/></figure><h3 id="gift-cards">Gift Cards</h3><p>Gift cards come built-in in Medusa. You can set an image for the gift card, manage how much the gift card is worth and add different worths for a gift card, and more.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-10-at-12.57.52-AM.png" class="kg-image" alt="Medusa: Create A Fast and Highly Customizable E-Commerce Store" loading="lazy" width="1478" height="1530" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-10-at-12.57.52-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-10-at-12.57.52-AM.png 1000w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-10-at-12.57.52-AM.png 1478w" sizes="(min-width: 720px) 720px"/></figure><h3 id="multiple-currencies">Multiple Currencies</h3><p>In Medusa, you can choose multiple currencies for your store and set a default one.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-10-at-1.00.21-AM.png" class="kg-image" alt="Medusa: Create A Fast and Highly Customizable E-Commerce Store" loading="lazy" width="802" height="650" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-10-at-1.00.21-AM.png 600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-10-at-1.00.21-AM.png 802w" sizes="(min-width: 720px) 720px"/></figure><h3 id="multiple-regions">Multiple Regions</h3><p>Medusa allows you to add multiple regions, each having its own countries that are part of the region, payment method, shipping method, currency, and more.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-10-at-1.00.43-AM.png" class="kg-image" alt="Medusa: Create A Fast and Highly Customizable E-Commerce Store" loading="lazy" width="2000" height="459" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-10-at-1.00.43-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-10-at-1.00.43-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-10-at-1.00.43-AM.png 1600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-10-at-1.00.43-AM.png 2146w" sizes="(min-width: 720px) 720px"/></figure><h2 id="medusas-strong-points">Medusa's Strong Points</h2><h3 id="blazingly-fast">Blazingly Fast</h3><p>As the frontend is decoupled from the backend, it removes the extra workload that is usually done in tightly coupled systems.</p><p>In addition, static site generators like Gatsby can be used to generate the storefront which would only need to connect to the backend through the REST APIs.</p><h3 id="highly-customizable">Highly Customizable</h3><p>The decoupling of the frontend from the backend allows you to customize your storefront freely. You can pick whatever programming language or framework you wish to use for the front end.</p><p>That's one of the benefits of headless commerce. You are free to focus on the front end and get creative with it without the shackles of the backend.</p><h3 id="easy-development">Easy Development</h3><p>One of the cons of a lot of popular e-commerce platforms is that they get too complicated or hard to learn. So, although they provide a lot of features that are enough to launch a store as is if you need to do any custom development you might need a lot of time to learn or understand its architecture.</p><p>Medusa is easy to use. In addition to the REST APIs available by default, you can easily add your own APIs. You can also create plugins to add missing functionalities or integrations that you need for your store.</p><h3 id="easy-setup-and-deployment">Easy Setup and Deployment</h3><p>You can set up a medusa store locally in a matter of minutes. With just 3 commands at most, you can have the backend, frontend, and admin dashboard all installed and ready to use.</p><p>Similarly, its deployment is easy as well. Medusa's documentation already has a guide on how to <a href="https://docs.medusa-commerce.com/how-to/deploying-on-heroku">deploy the backend on Heruko</a>, and the <a href="https://docs.medusa-commerce.com/how-to/deploying-admin-on-netlify">admin dashboard on Netlify</a>.</p><h2 id="medusas-cons">Medusa's Cons</h2><h3 id="no-internationalization">No Internationalization</h3><p>At the moment of writing this, Medusa does not support multiple languages. Internationalization is a very important aspect of e-commerce.</p><p>So, if your store needs to support languages other than the English language, then Medusa is not a good option.</p><p>Medusa's <a href="https://roadmap.medusa-commerce.com/c/8-localizations-api">roadmap</a> shows that Localization is a planned task. So, in the future, it should be available.</p><h3 id="lack-of-community-plugins">Lack of Community Plugins</h3><p>As Medusa is relatively new, at the moment there aren't many plugins created by the community to add custom functionalities to a Medusa store.</p><p>This is especially essential when it comes to payment and shipment integrations. Medusa comes with support for Stripe by default. Any additional payment or shipment services integration needs to be developed by you.</p><h3 id="simple-storefront">Simple Storefront</h3><p>Although we all love simplicity, the storefronts that Medusa currently provides are too simple. For example, although you can add multiple regions or currencies in the admin panel, there's no way to actually switch between them when using the storefronts Medusa provides.</p><p>This won't be a problem if you're mostly relying on Medusa's headless commerce backend, or you're looking to customize your frontend as necessary for you. However, if you need to use the frontend as is with additional development, then you need to consider this first.</p><h2 id="when-should-you-use-medusa">When Should You Use Medusa</h2><p>Medusa is the perfect option if you are looking for headless commerce. With its easy setup, you can have a headless commerce backend ready in a few minutes.</p><p>Medusa is also perfect if you're looking for complete freedom when designing your storefront. Even if you use one of its storefronts, you can easily make changes to the design as you find fitting.</p><p>Medusa is also one of the very few options available to build e-commerce stores with modern technologies.</p><h2 id="conclusion">Conclusion</h2><p>Medusa is still an evolving e-commerce platform. Yet, it still offers promising results compared to a lot of other e-commerce platforms when it comes to performance, customization, and other pros we've discussed throughout the article.</p><p>You can get started with Medusa in minutes with their <a href="https://docs.medusa-commerce.com/quickstart/quick-start">Quickstart documentation.</a></p>]]></content:encoded></item><item><title><![CDATA[5 Tips To Become A React Native Developer]]></title><description><![CDATA[If you are considering learning how to build android or iOS apps using React Native then this article is for you.]]></description><link>https://blog.shahednasser.com/5-tips-to-become-a-react-native-developer/</link><guid isPermaLink="false">Ghost__Post__615c9bad3eea8f060129b2cd</guid><category><![CDATA[React Native]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Chatty Garrate]]></dc:creator><pubDate>Thu, 07 Oct 2021 13:31:24 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/59e21af85472edb4c0a7f8177d97000f/christina-wocintechchat-com-R_W_9D-53lw-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/59e21af85472edb4c0a7f8177d97000f/christina-wocintechchat-com-R_W_9D-53lw-unsplash-2.jpg" alt="5 Tips To Become A React Native Developer"/><p><a href="https://reactnative.dev">React Native</a> is a cross-platform mobile application development framework. The main advantage of this technology is that you can use the same code base on all platforms without any changes. This makes your app more scalable and cost-effective because you don’t have to write separate codes for each device which will save time and money. </p><p><a href="https://andela.com/react-native-developers/">React Native developers</a> are in high demand these days because it has become one of the most popular technologies among web designers, front end engineers, and back-end programmers. If you are considering learning how to build android or iOS apps using React Native then this article is for you.</p><h2 id="what-is-react-native">What Is React Native?</h2><p>Before we can talk about becoming a React Native developer, let us first take a look at what exactly React Native is. It's a framework that allows developers to build cross-platform applications by combining web technologies like JavaScript along with native code written specifically for iOS or Android devices. </p><p>The reason why so many people have been switching over to React Native is that it has made creating cross-platform mobile apps much easier than ever before. With React Native, you no longer need to write separate codes for each operating system. Instead, you just develop one set of code that works across multiple platforms.</p><h2 id="tips-for-becoming-a-react-native-developer">Tips for Becoming a React Native Developer</h2><p>If you're thinking about learning to develop apps using React Native, there are several things you have to keep in mind. These tips will help you get started with the framework and become an expert developer in no time:</p><h3 id="learn-javascript-first">Learn JavaScript First</h3><p>Before starting on your journey of becoming a React Native developer, it's important that you learn how to program in general. This is because React Native uses JavaScript as its primary language. If you don't know JavaScript well enough, then this could be quite difficult for you. Learning JavaScript before getting into React Native can save you from having to deal with some common issues when developing apps.</p><p>You can learn JavaScript by reading books or online tutorials. There are many great resources available and the best way to find them is to search Google. You should also try to get familiar with other programming languages such as Java, Python, and C so that you have an idea about what they're like. The more experience you gain, the better prepared you'll be for learning React Native.</p><!--kg-card-begin: html--><a href="https://edabit.com/challenges/javascript?ref=shahednasser1&tap_a=86255-ae3f95" target="_BLANK" rel="nofollow"><img src="https://static.tapfiliate.com/5fcf4fb9056cd927104425.png?a=86255-ae3f95&s=2171241-632e37" border="0" alt="5 Tips To Become A React Native Developer"/></a><!--kg-card-end: html--><h3 id="understand-what-makes-react-native-different">Understand What Makes React Native Different</h3><p>When compared to other mobile app development platforms, React Native has a few unique features which make it stand apart. One such feature is that it allows developers to use native components, instead of building their own custom ones. And since React Native uses JavaScript as its primary language, you can build apps for iOS and Android using the same codebase. This makes your life much easier when developing an application because you don't have to write separate codes for each platform.</p><h3 id="familiarize-yourself-with-the-official-documentation">Familiarize Yourself with the Official Documentation</h3><p>The official docs contain all sorts of information regarding everything related to React Native. You should definitely spend time reading through them so that you understand every aspect of the platform. They also provide tutorials and guides for beginners who want to start off right away.</p><p>Watching or reading a <a href="https://blog.shahednasser.com/react-native-tutorial-create-your-first-app/">React Native tutorial</a> will also give you a good understanding of the basics of the framework. It will teach you how to create basic UI elements and connect them together. Once you've mastered these concepts, you can move on to advanced topics such as animations, data binding, and more.</p><h3 id="learning-about-navigation-concepts">Learning About Navigation Concepts</h3><p>As mentioned earlier, one of the most interesting aspects of React Native is that it provides access to many built-in navigation concepts. Both these methods work very similarly to those used in regular web applications. However, they allow us to build more complex user interfaces without needing to write much code ourselves.</p><p>Learning about different navigation concepts can be a bit overwhelming at first but once you understand them and how they are implemented, using them becomes second nature. This will help you get started with building your own apps faster.</p><h3 id="challenge-yourself-to-complete-react-native-projects">Challenge Yourself to Complete React Native Projects</h3><p>Learning any skill takes practice. So if you really want to master something, you need to put in lots of effort. To do this, challenge yourself to work on various projects with React Native. Try creating simple games or chat applications. Doing so will not only improve your skills but also expose you to new ideas and techniques.</p><p>If you feel stuck at any point while working on a particular task, reach out to your friends or colleagues. Ask them questions and see whether they can help you figure things out. Chances are, someone else might already have faced similar problems and solved them. In addition, asking people around you helps you develop confidence in your abilities.</p><h2 id="conclusion">Conclusion</h2><p>React Native is one of the most popular cross-platform frameworks that will allow you to create beautiful, highly performant apps, as well as find jobs easily in the market. <a href="https://blog.shahednasser.com/react-native-tutorial-create-your-first-app/">Start your journey now</a>!</p>]]></content:encoded></item><item><title><![CDATA[Top 9 Software Ideas for Start-Ups for The Year 2022]]></title><description><![CDATA[Given the rapid advancement of new technologies in recent years, the software development sector is one that should be pursued.]]></description><link>https://blog.shahednasser.com/top-9-software-ideas-for-start-ups-for-the-year-2022/</link><guid isPermaLink="false">Ghost__Post__615c29963eea8f060129b225</guid><category><![CDATA[Tips]]></category><category><![CDATA[Business]]></category><dc:creator><![CDATA[Akash Tripathi]]></dc:creator><pubDate>Tue, 05 Oct 2021 11:24:22 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/382c1a13ee4535f610bd499c71e81738/austin-distel-rxpThOwuVgE-unsplash-2-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/382c1a13ee4535f610bd499c71e81738/austin-distel-rxpThOwuVgE-unsplash-2-2.jpg" alt="Top 9 Software Ideas for Start-Ups for The Year 2022"/><p>Since the outbreak of the pandemic in March 2020, the use of new software technologies has grown at an amazing rate, increasing the need for custom software solution providers. These <a href="https://www.esparkinfo.com/custom-software-development.html">on-demand software development companies</a> have raised more than 200 percent of the developing cloud index's total capital and have a market value of around $2.4 trillion.</p><p>Given the rapid advancement of new technologies in recent years, the software development sector is one that should be pursued. As a result, these are the top 9 software ideas for start-ups in 2022.</p><h2 id="management-of-rental-properties">Management of Rental Properties</h2><p>Ownership of more than five homes or working as a real estate agent may make property management difficult. The goal is to develop an application that can assist an owner, a property agent, a renter, and a property joint management organization with the following:</p><ul><li>Rental collecting, reminders for payments, and receipts for payments.</li><li>For smooth payment collection, integrate online payment and e-wallet.</li><li>Upkeep and repair.</li><li>Management of complaints and feedback.</li><li>Management by commission.</li></ul><h2 id="investor-journal">Investor Journal</h2><p>Investors are advised to keep track of their buy and sell orders so they may look back and reflect on the lessons they've learned.</p><p>Using the collected expertise stored in this program, investors may revise and examine previous investments in order to enhance their performance.</p><h2 id="chatbot-solution-powered-by-virtual-ai">Chatbot Solution Powered by Virtual AI</h2><p>Since 2014, the number of people who shop digitally has increased dramatically.</p><p>In 2021, there will be 2.14 billion digital purchasers out of a total population of 7.78 billion, a 4.4 percent growth year over year.</p><p>Eventually, every firm will have to go online. A chatbot and virtual assistant will dramatically enhance the customer experience, conversion, and selling. It would be ideal if it could link to the most popular social media platforms such as Instagram, Facebook, Telegram, WhatsApp, and WeChat to enable seamless automation.</p><h2 id="collaborative-tool-for-teams-and-platform-for-team-development">Collaborative Tool for Teams and Platform for Team Development</h2><p>Working from home has become the new normal for employees worldwide. Companies require tools for team collaboration in order to maintain team cohesion, smooth task delegation, project management, and documentation.</p><p>The global market for team collaboration software is estimated at $27.8 billion by 2028 as per <a href="https://www.globenewswire.com/news-release/2021/07/27/2269668/0/en/Team-Collaboration-Software-Market-Value-Predicted-To-Reach-US-27-8-Billion-By-2028-Covering-COVID-19-ERA-Acumen-Research-and-Consulting.html">Global Newswire</a>.</p><p>Additionally, 24% of respondents reported experiencing video meeting fatigue, 19% report having difficulty interacting in real-time (preferring not to connect through email or messenger), and 17% report finding it more difficult to manage professional relationships. – <a href="https://www.flexjobs.com/blog/post/flexjobs-survey-finds-employees-want-remote-work-post-pandemic/">Survey conducted by Flexjobs</a>.</p><p>A platform for team development would greatly enhance communication and relationships among team members. To keep users socially engaged, the platform can incorporate aspects of different gaming activities (such as the game depicted above), team interaction capabilities, beautiful visuals, and music.</p><p>Despite the fact that there are many collaborations and team-building technologies available on the market, demand for them continues to grow at an exponential rate.</p><h2 id="develop-a-medical-software-program">Develop a Medical Software Program</h2><p>Medical Software manages patients' computerized medical records. Numerous clinics and hospitals seek an alternative to error-prone manual patient data input. In this way, you may educate clinics and hospitals about the advantages of the medical software you're developing and sell them on it.</p><p>By Statista, <a href="https://www.statista.com/statistics/866501/medical-imaging-analytics-software-market-size-worldwide/">medical software is predicted to reach $4.26 billion</a> in global sales by 2025. As can be seen, there are several changes in this field. There are many healthcare <a href="https://www.topmobiletech.com/top-software-development-companies/">software development businesses</a> that may assist you in developing medical software and bringing your idea to life.</p><!--kg-card-begin: html--><a href="https://yiro6gzu369.typeform.com/to/bmKKNVlh"><img src="https://res.cloudinary.com/shahed/image/upload/v1633434557/Place_your_Ad_here_178_x_100_px_-3_kvf6uo.png" alt="Top 9 Software Ideas for Start-Ups for The Year 2022"/></a><!--kg-card-end: html--><h2 id="itinerary-maker-for-trips">Itinerary Maker for Trips</h2><p>Although the tourist business appears to be suffering at the moment, this sector is poised for rapid expansion after the epidemic is over.</p><p>It may be hard to plan a trip schedule. We'll need distance, location, suggestions, and budget information to decide which POIs (points of interest) fit within the schedule.</p><p>When using a trip itinerary planner, all of the relevant information is gathered in one location, and destinations can be effortlessly dragged and dropped. It is preferable if the planner can automatically optimize the schedule for distance and cost of travel. Additionally, posting tailored vacation itineraries will significantly boost the platform's network impact.</p><h2 id="solutions-for-email-delivery">Solutions for Email Delivery</h2><p>Modern life is dominated by online activities such as shopping, ordering takeout or delivery, communicating, participating in sports, banking, and attending meetings or conventions. When it comes to transactional services like registration of an account, reset the password, confirmation, financial transactions, and marketing, email delivery plays a critical role.</p><p>Numerous enhancements are possible, including user interface, ease of setup, customer experience, and cost.</p><h2 id="password-organiser">Password Organiser</h2><p>There are <a href="https://www.socialmediatoday.com/news/60-fascinating-smartphone-apps-usage-statistics-for-2019-infographic/550990/">80 applications on average for every smartphone user</a>. In other words, users will have to keep track of at least 80 distinct sets of login credentials. Password reuse is a security risk because even if one app database is compromised, it might compromise other accounts that use the same password.</p><p>Password manager solves this problem by assisting you in creating and remembering a unique password for each account. Then, secure the master account using several levels of security, such as two-factor verification or Google Authentication protocol.</p><h2 id="platform-for-online-training-and-coaching">Platform for Online Training and Coaching</h2><p>Since the epidemic, many individuals worldwide have begun teaching online and providing coaching services. It's reasonable to manage all members on a personal Facebook page, but branding, professionalism, and a payment mechanism are all missing in action.</p><p>The purpose of this platform is to enable coaches to post multimedia recordings, lectures, and tutoring sessions. Exams, quizzes, and completion certificates can all be used to engage pupils. Automated membership money collection from subscribers, allowing the coach to focus on providing outstanding material instead.</p><h2 id="conclusion">Conclusion</h2><p>While software products may expand at an insane rate due to their extensibility as software, the work and expense associated with developing effective software can be rather high. Create a minimum viable product (MVP) first, and then get some early consumers on board to offer you valuable feedback.</p>]]></content:encoded></item><item><title><![CDATA[How to Style a Video Player and Create a Custom Player]]></title><description><![CDATA[In this tutorial, we'll learn how to style a video element with CSS and how to create a custom video player.]]></description><link>https://blog.shahednasser.com/how-to-style-a-video-player-and-create-a-custom-player/</link><guid isPermaLink="false">Ghost__Post__6156dfc23eea8f060129b071</guid><category><![CDATA[CSS]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 04 Oct 2021 14:46:31 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/48bf768094abd995b0b61cf402bd0a1d/onur-binay-WIJi--orNc4-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/48bf768094abd995b0b61cf402bd0a1d/onur-binay-WIJi--orNc4-unsplash-2.jpg" alt="How to Style a Video Player and Create a Custom Player"/><p>In a previous tutorial, we looked into how to style an audio element with CSS. We looked at how to do it with the audio's pseudo-selectors, and how to create an audio player of our own for more flexibility in styling it.</p><p>In this tutorial, we'll learn how to style a video element with CSS. Similar to the previous tutorial, we'll see how to do it with pseudo selectors and how to create a video player of our own.</p><h2 id="using-pseudo-element-selectors">Using Pseudo-Element Selectors</h2><p>Video elements, by default, is not visible. We need to add the <code class="language-text">controls</code> attribute to the HTML tag to make it visible.</p><h3 id="default-video-element">Default Video Element</h3><p>By default, here's how a video element looks like:</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_YzQdBOR" src="https://codepen.io/shahednasser/embed/preview/YzQdBOR?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=YzQdBOR" title="Default Video Style" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><p>Notice that the default video element looks different on every browser.</p><h3 id="video-pseudo-element-selectors">Video Pseudo-Element Selectors</h3><p>Here are the video pseudo-element selectors that we can use to style a video element:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-panel <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-play-button <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-volume-slider-container <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-volume-slider <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-mute-button <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-timeline <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-current-time-display <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token property">-webkit-full-page-media</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-panel <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-timeline-container <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-time-remaining-display <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-seek-back-button <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-seek-forward-button <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-fullscreen-button <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-rewind-button <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-return-to-realtime-button <span class="token property">video</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-toggle-closed-captions-button</code></pre></div><p>However, we'll see in the examples below that styling with these selectors mostly only works with Chrome.</p><p>So, it's recommended to view the examples below on Chrome to see how the styling works.</p><h3 id="style-video-player-general-container">Style Video Player General Container</h3><p>To style a video player's general container, which includes all of the elements in a video player, we can use the pseudo-element selector <code class="language-text">video::-webkit-media-controls-panel</code>. In the example below, we use it to change the background color of the video player.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_NWgJQJy" src="https://codepen.io/shahednasser/embed/preview/NWgJQJy?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=NWgJQJy" title="Change Video Player Background" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h3 id="style-play-button">Style Play Button</h3><p>To style a video player's play button, we can use the pseudo-element selector <code class="language-text">video::-webkit-media-controls-play-button</code>. In the example below, we add a background color and a border-radius to the play button.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_qBjvezd" src="https://codepen.io/shahednasser/embed/preview/qBjvezd?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=qBjvezd" title="Style Play Button" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h3 id="style-volume-slider">Style Volume Slider</h3><p>To style a volume slider, we can use the pseudo-element selector <code class="language-text">video::-webkit-media-controls-volume-slider</code>. In the example below, we add a background color to the volume slider as well as make some changes in its padding and margin.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_ExXJYxY" src="https://codepen.io/shahednasser/embed/preview/ExXJYxY?default-tabs=css%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=ExXJYxY" title="Style volume slider" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h3 id="style-mute-button">Style Mute Button</h3><p>To style the mute button, we can use the pseudo-element selector <code class="language-text">video::-webkit-media-controls-mute-button</code>. In the example below, we add a background color as well as a border-radius to the mute button.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_NWgmKYe" src="https://codepen.io/shahednasser/embed/preview/NWgmKYe?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=NWgmKYe" title="Styling Mute Button" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h3 id="style-timeline">Style Timeline</h3><p>To style the timeline of the video, we can use the pseudo-element selector <code class="language-text">video::-webkit-media-controls-timeline</code>. In the example below, we add a background color as well as play with the padding and margin of the timeline.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_mdwgbLx" src="https://codepen.io/shahednasser/embed/preview/mdwgbLx?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=mdwgbLx" title="Styling Timeline" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h3 id="style-current-time">Style Current Time</h3><p>To style the current time of the video, we can use the pseudo-element selector <code class="language-text">video::-webkit-media-controls-current-time-display</code>. In the example below, we change the text color of the current time.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_yLXrBEB" src="https://codepen.io/shahednasser/embed/preview/yLXrBEB?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=yLXrBEB" title="Styling Current Time" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h3 id="style-remaining-time">Style Remaining Time</h3><p>To style the remaining time of the video, we can use the pseudo-element selector <code class="language-text">video::-webkit-media-controls-time-remaining-display</code>. In the example below, we change the text color of the remaining time.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_YzQMKvE" src="https://codepen.io/shahednasser/embed/preview/YzQMKvE?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=YzQMKvE" title="Styling Remaining Time" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h3 id="style-the-full-screen-button">Style the Full-Screen Button</h3><p>To style the full-screen button of the video player, we can use the pseudo-element selector <code class="language-text">video::-webkit-media-controls-fullscreen-button</code>. In the example below, we change the background color as well as the border radius of the button.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_GRELKBd" src="https://codepen.io/shahednasser/embed/preview/GRELKBd?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=GRELKBd" title="Styling Full Screen Button" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h2 id="create-custom-player">Create Custom Player</h2><p>In this section, we'll cover how to create a custom video player. Creating a custom video player guarantees that the video looks the same on all browsers, rather than our styling being supported by some browsers and not others.</p><p>When creating a custom player, that means we also have to add the wiring in JavaScript to make sure all the video functionalities are added to the video.</p><p>We'll start first with the styling then move on to the JavaScript. You can find the full video player at the end of this section.</p><p>The video is from <a href="https://www.w3schools.com/html/mov_bbb.mp4">W3Schools</a> and the icons are from <a href="https://heroicons.com">Heroicons</a>.</p><h3 id="style-with-css">Style with CSS</h3><p>We'll first add the video inside a <code class="language-text">div</code> element, which will be the container for the video element and the controls:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>video-player<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>video</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>video<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>source</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://www.w3schools.com/html/mov_bbb.mp4<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>video/mp4<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>video</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre></div><p>Then, we'll add a simple styling related to the sizing of the video element:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.video-player</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 30rem<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 16.5rem<span class="token punctuation">;</span> <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">video</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">background</span><span class="token punctuation">:</span>black<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will show the video, but it will not have any controls so we cannot interact with it yet.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-04-at-4.53.20-PM.png" class="kg-image" alt="How to Style a Video Player and Create a Custom Player" loading="lazy" width="988" height="548" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-04-at-4.53.20-PM.png 600w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-04-at-4.53.20-PM.png 988w" sizes="(min-width: 720px) 720px"/></figure><p>Next, we'll add the controls. Add the following after the video element:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>controls<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>play-button control-button<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>svg</span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>h-5 w-5<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 20 20<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>currentColor<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>path</span> <span class="token attr-name">fill-rule</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>evenodd<span class="token punctuation">"</span></span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z<span class="token punctuation">"</span></span> <span class="token attr-name">clip-rule</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>evenodd<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>svg</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>range<span class="token punctuation">"</span></span> <span class="token attr-name">min</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">max</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>100<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>timeline<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sound-button control-button<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>svg</span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>none<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 24 24<span class="token punctuation">"</span></span> <span class="token attr-name">stroke</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>currentColor<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>path</span> <span class="token attr-name">stroke-linecap</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>round<span class="token punctuation">"</span></span> <span class="token attr-name">stroke-linejoin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>round<span class="token punctuation">"</span></span> <span class="token attr-name">stroke-width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 12.728M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>svg</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>control-button fullscreen-button<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>svg</span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>h-6 w-6<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>none<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 24 24<span class="token punctuation">"</span></span> <span class="token attr-name">stroke</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>currentColor<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>path</span> <span class="token attr-name">stroke-linecap</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>round<span class="token punctuation">"</span></span> <span class="token attr-name">stroke-linejoin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>round<span class="token punctuation">"</span></span> <span class="token attr-name">stroke-width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>svg</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre></div><p>This includes a play button, the timeline as a range element, a sound element to mute and unmute the video, and a full-screen button.</p><p>First, we'll add styling for the container of the controls. Add the following CSS:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.controls</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">bottom</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span>to bottom<span class="token punctuation">,</span> transparent<span class="token punctuation">,</span> #000<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token property">transition</span><span class="token punctuation">:</span> opacity .2s<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will make the display <code class="language-text">flex</code> to ensure the items are placed next to each other perfectly. It will also position the controls at the bottom of the video and add a gradient background that goes from transparent to black.</p><p>We'll also add some CSS to hide the controls when the video is playing and only show them on hover:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.video-player.playing .controls</span> <span class="token punctuation">{</span> <span class="token property">opacity</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.video-player:hover .controls</span> <span class="token punctuation">{</span> <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Next, we'll style the buttons. We'll add general styling that will be common for all the buttons:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.control-button</span> <span class="token punctuation">{</span> <span class="token property">border</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">background</span><span class="token punctuation">:</span> transparent<span class="token punctuation">;</span> <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span> <span class="token property">opacity</span><span class="token punctuation">:</span> .8<span class="token punctuation">;</span> <span class="token property">transition</span><span class="token punctuation">:</span> all .2s<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.control-button:hover</span> <span class="token punctuation">{</span> <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.control-button svg</span> <span class="token punctuation">{</span> <span class="token property">stroke</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span> <span class="token property">fill</span><span class="token punctuation">:</span> transparent<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will remove the default background color and border of a button and add some nice opacity transition on hover. We're also setting the <code class="language-text">stroke</code> and <code class="language-text">fill</code> of the SVG icons inside the buttons.</p><p>Then, we'll add more specific styling for each of the buttons to specify the size of the icons. This is just because some of the buttons can be bigger than the others:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.control-button.play-button</span> <span class="token punctuation">{</span> <span class="token property">height</span><span class="token punctuation">:</span> 40px<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 40px<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.control-button.sound-button</span> <span class="token punctuation">{</span> <span class="token property">height</span><span class="token punctuation">:</span> 40px<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 40px<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.control-button.fullscreen-button</span> <span class="token punctuation">{</span> <span class="token property">height</span><span class="token punctuation">:</span> 35px<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 35px<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Finally, we need to style the timeline. The timeline is an input range element.</p><p>To style a range input element, we can use the following CSS pseudo-selectors:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css">.<span class="token property">timeline</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-slider-thumb .<span class="token property">timeline</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-moz-range-thumb .<span class="token property">timeline</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-ms-thumb .<span class="token property">timeline</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-slider-runnable-track .<span class="token property">timeline</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-moz-range-track .<span class="token property">timeline</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-ms-track</code></pre></div><p>The first three are cross-browser pseudo-selectors for the thumb which is used to change the range value. The second three are cross-browser pseudo-selectors for the track of the range input.</p><p>We'll first add styling to the timeline range element as a whole:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.timeline</span> <span class="token punctuation">{</span> <span class="token property">-webkit-appearance</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>100% - 125px<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> .5em<span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span>255<span class="token punctuation">,</span> 255<span class="token punctuation">,</span> 255<span class="token punctuation">,</span> .3<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">border-radius</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span> <span class="token property">background-size</span><span class="token punctuation">:</span> 0% 100%<span class="token punctuation">;</span> <span class="token property">background-image</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span>#fff<span class="token punctuation">,</span> #fff<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">background-repeat</span><span class="token punctuation">:</span> no-repeat<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will set the width to <code class="language-text">100% - 125px</code>, where <code class="language-text">125px</code> is the width of the buttons combined with extra space. We also set the background color of the track.</p><p>Notice that we use the <code class="language-text">background-image</code> attribute to indicate the time elapsed in the video. <code class="language-text">background-size</code> will be used to indicate the progress of the video. In the beginning, it's <code class="language-text">0%</code>. Later on, we'll change <code class="language-text">background-size</code> based on the video progress in JavaScript.</p><p>Next, we'll style the thumb used to change the current time of the video:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.timeline::-webkit-slider-thumb</span> <span class="token punctuation">{</span> <span class="token property">-webkit-appearance</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 1em<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 1em<span class="token punctuation">;</span> <span class="token property">border-radius</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span> <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span> <span class="token property">opacity</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">transition</span><span class="token punctuation">:</span> all .1s<span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span>255<span class="token punctuation">,</span> 255<span class="token punctuation">,</span> 255<span class="token punctuation">,</span> .8<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.timeline::-moz-range-thumb</span> <span class="token punctuation">{</span> <span class="token property">-webkit-appearance</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 1em<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 1em<span class="token punctuation">;</span> <span class="token property">border-radius</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span> <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span> <span class="token property">opacity</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">transition</span><span class="token punctuation">:</span> all .1s<span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span>255<span class="token punctuation">,</span> 255<span class="token punctuation">,</span> 255<span class="token punctuation">,</span> .8<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.timeline::-ms-thumb</span> <span class="token punctuation">{</span> <span class="token property">-webkit-appearance</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 1em<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 1em<span class="token punctuation">;</span> <span class="token property">border-radius</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span> <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span> <span class="token property">opacity</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">transition</span><span class="token punctuation">:</span> all .1s<span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span>255<span class="token punctuation">,</span> 255<span class="token punctuation">,</span> 255<span class="token punctuation">,</span> .8<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.timeline::-webkit-slider-thumb:hover</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.timeline:hover::-webkit-slider-thumb</span> <span class="token punctuation">{</span> <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.timeline::-moz-range-thumb:hover</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.timeline:hover::-moz-range-thumb</span> <span class="token punctuation">{</span> <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.timeline::-ms-thumb:hover</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.timeline:hover::-ms-thumb</span> <span class="token punctuation">{</span> <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This sets its color to white with some opacity. Then, on hover, we set the opacity to <code class="language-text">1</code>. Note that the style properties are repeated for cross-platform pseudo-selectors. We are also setting the width, height, border-radius, and more.</p><p>Finally, we'll style the track of the timeline:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.timeline::-webkit-slider-runnable-track</span> <span class="token punctuation">{</span> <span class="token property">-webkit-appearance</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">box-shadow</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">border</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">background</span><span class="token punctuation">:</span> transparent<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.timeline::-moz-range-track</span> <span class="token punctuation">{</span> <span class="token property">-webkit-appearance</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">box-shadow</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">border</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">background</span><span class="token punctuation">:</span> transparent<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.timeline::-ms-track</span> <span class="token punctuation">{</span> <span class="token property">-webkit-appearance</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">box-shadow</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">border</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">background</span><span class="token punctuation">:</span> transparent<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This just removes the default appearance of the track.</p><p>Our player is visually ready and should look like this:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-04-at-5.15.42-PM.png" class="kg-image" alt="How to Style a Video Player and Create a Custom Player" loading="lazy" width="1004" height="564" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-04-at-5.15.42-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-04-at-5.15.42-PM.png 1000w, https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-04-at-5.15.42-PM.png 1004w" sizes="(min-width: 720px) 720px"/></figure><p>What's left is to wire the controls with JavaScript and add the video functionalities.</p><h3 id="add-functionalities-with-javascript">Add Functionalities With JavaScript</h3><p>We'll start by declaring some variables we'll use in our code. We'll declare variables related to the icons of the buttons:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> play <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" /> </svg></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> <span class="token keyword">const</span> pause <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 9v6m4-6v6m7-3a9 9 0 11-18 0 9 9 0 0118 0z" /> </svg></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> <span class="token keyword">const</span> sound <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 12.728M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z" /> </svg></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> <span class="token keyword">const</span> mute <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z" clip-rule="evenodd" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2" /> </svg></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></code></pre></div><p>The reason we're declaring them in JavaScript is to change between pause and play icons based on whether the video is playing or not, and to change between sound and mute icons based on whether the video is muted or not.</p><p>Then, we'll declare variables for the HTML elements we created to be able to attach event listeners and more:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> playButton <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.play-button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> video <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'video'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> timeline <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.timeline'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> soundButton <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.sound-button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> fullscreenButton <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.fullscreen-button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> videoContainer <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.video-player'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> isFullScreen <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></code></pre></div><p>We've also added the <code class="language-text">isFullScreen</code> variable which we'll use later to toggle full-screen states.</p><p>We'll start with the most basic functionality in a video player which is playing or pausing the video. We'll add an event listener to the click event of the <code class="language-text">playButton</code>. Inside the listener, we'll check if the video is paused or not with the property <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/paused">paused</a> on video and media elements:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">playButton<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>video<span class="token punctuation">.</span>paused<span class="token punctuation">)</span> <span class="token punctuation">{</span> video<span class="token punctuation">.</span><span class="token function">play</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> videoContainer<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">'playing'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> playButton<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> pause<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> video<span class="token punctuation">.</span><span class="token function">pause</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> videoContainer<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">'playing'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> playButton<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> play<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>If the video is paused, we play it, we add the class <code class="language-text">playing</code> to the video container, and we change the icon to the pause icon. The reason we add the class <code class="language-text">playing</code> is that in the CSS earlier we added styling to hide the controls when the video is playing.</p><p>If you try it out now, you'll see that the video player now allows you to play and pause the video.</p><p>We'll also add a listener to the <code class="language-text">onended</code> event, which is triggered when the video ends, to change the icon back to play:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">video<span class="token punctuation">.</span><span class="token function-variable function">onended</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> playButton<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> play<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Next, we'll add the functionality for the timeline. We'll first add a listener to the media element event <code class="language-text">ontimeupdate</code> which is triggered as the video is playing to indicate the current time of the video is changing. We'll use it to change the background size of the timeline track as we mentioned above in the CSS section:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">video<span class="token punctuation">.</span><span class="token function-variable function">ontimeupdate</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> percentagePosition <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">100</span><span class="token operator">*</span>video<span class="token punctuation">.</span>currentTime<span class="token punctuation">)</span> <span class="token operator">/</span> video<span class="token punctuation">.</span>duration<span class="token punctuation">;</span> timeline<span class="token punctuation">.</span>style<span class="token punctuation">.</span>backgroundSize <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>percentagePosition<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">% 100%</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> timeline<span class="token punctuation">.</span>value <span class="token operator">=</span> percentagePosition<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>We use <code class="language-text">video.currentTime</code> and <code class="language-text">video.duration</code> to calculate the progress in percentage then change the value of the timeline range element and its <code class="language-text">background-size</code> CSS property based on that percentage.</p><p>We'll also add a listener to the <code class="language-text">change</code> event on the timeline range element. When the user drags the thumb the video's current time should change based on the position the user chose:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">timeline<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'change'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> time <span class="token operator">=</span> <span class="token punctuation">(</span>timeline<span class="token punctuation">.</span>value <span class="token operator">*</span> video<span class="token punctuation">.</span>duration<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">100</span><span class="token punctuation">;</span> video<span class="token punctuation">.</span>currentTime <span class="token operator">=</span> time<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>If you test it now, you'll see that as the video progresses you'll be able to see the progress in the timeline element. You can also seek the video using the timeline.</p><p>Next, we'll add functionality to the sound button. When clicking on it, in the listener we will mute the video if it has sound and unmute it if the opposite. We'll also change the icon of the sound button based on whether the video is muted or not:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">soundButton<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> video<span class="token punctuation">.</span>muted <span class="token operator">=</span> <span class="token operator">!</span>video<span class="token punctuation">.</span>muted<span class="token punctuation">;</span> soundButton<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> video<span class="token punctuation">.</span>muted <span class="token operator">?</span> mute <span class="token operator">:</span> sound<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Notice that we use <code class="language-text">video.muted</code> to determine if the video is currently muted and to change whether it is muted or not.</p><p>If you test it now, you should be able to mute and unmute the video using the sound button.</p><p>Finally, we'll add the functionality of the full-screen button. When the button is clicked, we'll check if the video is in full screen using the variable <code class="language-text">isFullScreen</code>. If the video is not in full-screen, we make it full screen. If it's already in full-screen we exit full screen:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">fullscreenButton<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>isFullScreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>video<span class="token punctuation">.</span>requestFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> video<span class="token punctuation">.</span><span class="token function">requestFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>video<span class="token punctuation">.</span>webkitRequestFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/* Safari */</span> video<span class="token punctuation">.</span><span class="token function">webkitRequestFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>video<span class="token punctuation">.</span>msRequestFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/* IE11 */</span> video<span class="token punctuation">.</span><span class="token function">msRequestFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>document<span class="token punctuation">.</span>exitFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span><span class="token function">exitFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>document<span class="token punctuation">.</span>webkitExitFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/* Safari */</span> document<span class="token punctuation">.</span><span class="token function">webkitExitFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>document<span class="token punctuation">.</span>msExitFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/* IE11 */</span> document<span class="token punctuation">.</span><span class="token function">msExitFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Note that when making the video full screen we use <code class="language-text">requestFullscreen</code>, <code class="language-text">webkitRequestFullscreen</code> or <code class="language-text">msRequestFullScreen</code> based on what the current browser supports. Similarly, to exit full screen we use <code class="language-text">document.exitFullscreen</code>, <code class="language-text">document.webkitExitFullscreen</code>, or <code class="language-text">document.msExitFullscreen</code> based on what the current browser supports.</p><p>If you test the full-screen button now, you should be able to switch to and from full screen for the video.</p><h3 id="final-video-player">Final Video Player</h3><p>Our video is now fully operational with play, pause, mute, unmute, full-screen, and seek functionalities. You can see the full video player below:</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_xxrNEaM" src="https://codepen.io/shahednasser/embed/preview/xxrNEaM?default-tabs=js%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=xxrNEaM" title="Custom Video" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h2 id="conclusion">Conclusion</h2><p>When styling video elements, you can use pseudo-selectors. However, the styling will not be supported by all browsers and the same player styling is not guaranteed.</p><p>Instead, you'll need to create your own custom video player like we did above. You can add as many functionalities as you want. Creating your own custom player is a far more flexible and better solution.</p>]]></content:encoded></item><item><title><![CDATA[Django vs Node.js: Which One Is Better For Web Development?]]></title><description><![CDATA[In this blog, we will take you through the definition of the frameworks, the key advantages and disadvantages of these frameworks, and compare them.]]></description><link>https://blog.shahednasser.com/django-vs-node-js-which-one-is-better-for-web-development/</link><guid isPermaLink="false">Ghost__Post__6156eb0a3eea8f060129b0e3</guid><category><![CDATA[Javascript]]></category><category><![CDATA[Python]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Harikrishna Kundariya]]></dc:creator><pubDate>Fri, 01 Oct 2021 11:14:00 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/43d13f5675109f73bbf99d32048ebe00/image2.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/43d13f5675109f73bbf99d32048ebe00/image2.png" alt="Django vs Node.js: Which One Is Better For Web Development?"/><p>Choosing the right developing tool may not always be a piece of cake. Especially if they fall in the same category and are equally popular like Node.js and Django frameworks.</p><p>Node.js and Django are the most popular open-source frameworks used for building web applications.</p><p>Node.js is based on Javascript while Django is Python-based. Both the frameworks may have the same purpose but they have unique features and functionalities.</p><p>In this blog, we will take you through the definition of the frameworks, key advantages and disadvantages of these frameworks.</p><p>In the end, we will compare both these frameworks on the major parameters like programming, flexibility, architecture, security, performance, and more. So let’s dive in!</p><h2 id="django">Django</h2><p>Django is a high-level, open-source Python web development framework. It is a free framework whose design is based on the traditional model-view-controller (MVC) architecture.</p><p>Django functions on the model-template view architecture pattern, with which developers can build a robust backend to your web app in a very short span of time.</p><p>Although Django is mostly preferred for backend needs, it can also be used for building a full-stack web app at the front-end when used with HTML/CSS/Javascript.</p><h3 id="recognized-brand-using-this-framework%E2%80%8C%E2%80%8C">Recognized brand using this framework</h3><ul><li>Instagram</li><li>National Geographic</li><li>Mozilla</li><li>Spotify</li><li>Pinterest</li><li>Disqus</li><li>Bitbucket</li><li>Eventbrite</li><li>Prezi</li></ul><h3 id="benefits-of-django-framework-%E2%80%8C%E2%80%8C">Benefits of Django framework </h3><ul><li>Django is not only easy to implement but also an easy learning framework. Anyone who knows the basic python language can learn this framework.</li><li>The framework is designed to implement high-level processes.</li><li>The built-in templates framework enables quick development.</li><li>It is highly reliable in terms of security.</li></ul><h3 id="drawbacks-of-django%E2%80%8C%E2%80%8C%E2%80%8C%E2%80%8C">Drawbacks of Django</h3><ul><li>Django framework is an extensive framework that requires a lot of code. This makes it less suitable for websites with low bandwidth.</li><li>The framework only works with single-layered applications.</li><li>Django works fine with big projects but when it comes to developing smaller projects with only a few features, its performance can deteriorate.</li><li>It cannot handle multiple requests for individual processes at once. </li></ul><!--kg-card-begin: html--><a href="https://edabit.com/challenges/python3?ref=shahednasser1&tap_a=86253-722f0d" target="_BLANK" rel="nofollow"><img src="https://static.tapfiliate.com/5fcf4fb90c564491563884.png?a=86253-722f0d&s=2171241-632e37" border="0" alt="Django vs Node.js: Which One Is Better For Web Development?"/></a><!--kg-card-end: html--><h2 id="nodejs">Node.js</h2><p>Node.js is a cross-platform, open-source JavaScript runtime environment. The JavaScript code is exhibited outside a web portal. The framework was designed in 2009 and is based on Javascript, C, and C++. </p><p>The framework enables developers to write commonly on both server-side and client-side. It works well for building scalable network applications through an event-driven, I/O model. This model makes Nodejs a quick and light resource for <a href="https://www.topmobiletech.com/top-web-development-companies/">web app development</a>. </p><h3 id="recognized-brand-using-this-framework%E2%80%8C%E2%80%8C-1">Recognized brand using this framework</h3><ul><li>LinkedIn</li><li>Netflix</li><li>Medium</li><li>Groupon</li><li>Walmart</li><li>Uber</li><li>Trello</li><li>PayPal</li><li>NASA</li><li>eBay</li><li>GoDaddy</li></ul><h3 id="benefits-of-using-nodejs-%E2%80%8C%E2%80%8C">Benefits of using Node.js </h3><ul><li>Application developed with Nodejs is easy to scale in both vertical and horizontal directions.</li><li>It is a single programming language that can be used for both front-end and back-end web development.</li><li>Node.js is a huge global community, where millions of developers contribute to solving peculiar development errors.</li><li>It is simple to use the framework with minimal highlight complications.</li><li>When you <a href="https://www.esparkinfo.com/web-app-development/node-js.html">hire experienced Node js Developers,</a> they can create any kind of apps and software. </li></ul><h3 id="drawbacks-of-nodejs%E2%80%8C%E2%80%8C%E2%80%8C%E2%80%8C">Drawbacks of Nodejs</h3><ul><li>API- Application Programming interface changes frequently which enables heavy code change.</li><li>It can be expensive and need high skills and effort in creating high-end applications.</li><li>Can have security defects.</li><li>Several developers find the non-coordinated programming of Nodejs hard. Performance gets reduced when it comes to handling heavy CPU-based tasks.It does not work very well with serious application and may consist of an inferable single-thread framework.</li></ul><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/image1.png" class="kg-image" alt="Django vs Node.js: Which One Is Better For Web Development?" loading="lazy" width="650" height="499" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/image1.png 600w, https://backend.shahednasser.com/content/images/2021/10/image1.png 650w"/></figure><h3 id="decoding-the-major-difference-between-django-and-nodejs">Decoding the major difference between Django and Node.js</h3><p>Although Django and Nodejs have many differences, both frameworks are popular developing technologies with versatile use.</p><p>We have curated a simplified list of parameters for you to compare Nodejs and Django as per your requirement.</p><p>If we have to define one big difference between these two frameworks then this would be the following:</p><p>A high-level Python framework enables developers to make rapid development and build web applications at high speed. <br><br>Whereas Node.js is a JavaScript framework that is majorly used to function on client-side web applications.</br></br></p><p>With the Node.js framework, developers can choose to execute code in a private server instead of a web browser. This is not the case with Django.</p><p>Here is a brief comparison of Nodejs and Django framework on different parameters: </p><h3 id="architecture">Architecture<br/></h3><p>Django works on the MTV model.</p><p>Nodejs works on an event-driven model.</p><h3 id="security">Security<br/></h3><p>The built-in system of the Django framework makes it more secure compared to NodeJs.</p><p>Unlike Django, the Nodejs framework requires manual operation in a system which makes it less reliable in terms of security</p><h3 id="performance">Performance<br/></h3><p>Again, the built-in template property of Django enables faster execution, which means good performance. </p><p>Unlike Django, in Nodejs there is no limitation of using built-in templates. Developers can enhance the performance of the website as per their preference. This can affect the development time though. So if you want a quick implementation framework you can skip this one. </p><h3 id="complexity">Complexity<br/></h3><p>With the Django framework, developers are limited to work on a fixed pathway.</p><p>Nodejs is not as complicated as Django. Here developers have a free hand in solving any problem.</p><h3 id="cost-efficiency">Cost-efficiency<br/></h3><p>Django is quick to implement framework; this makes it quick to use as well as cost-efficient. </p><p>Nodejs might be more expensive than Django but it is popular for steady growth. </p><h3 id="community">Community<br/></h3><p>Django has a comparatively small community of developers. </p><p>NodeJS consists of a huge community of developers, which is widespread across the world. The community offers regular updates and bug acids. </p><h3 id="full-stack-development">Full-stack development?<br/></h3><p>Django is not suitable for full-stack development.</p><p>Node.js is based on a javascript programming language with the proficiency to be used for both frontend and backend development. This makes the framework a highly opted technology for full-stack web application needs.</p><h3 id="flexibility">Flexibility<br/></h3><p>Django features built-in templates, which brings limitations to customization features. </p><p>The javascript-based node.js framework brings with it several tools and features that provide developers freedom of customization and build an app from scratch.</p><h3 id="which-language-to-choose">Which Language to Choose?<br/></h3><p>There are no specific parameters when it comes to choosing a technology for your mobile and web development needs. Every website or mobile app has a specific requirement that aligns with business needs and the end-users. Also, the preference of developers also needs to be considered.</p><p>The above-mentioned information and details will help you understand the key benefits and drawbacks of each framework. So you can choose best based on your application requirements. </p><p>The more clear you are with the website requirement, the better clarity you will have in selecting a framework. Developers can then develop better applications with distinguished features considering primary and secure functionalities. </p><h3 id="conclusion">Conclusion</h3><p>The method and tools used by development can for sure define the success of web applications. Node.js and Django are highly advanced frameworks popular with unique benefits and features. </p><p>You should choose on the basis of the above-mentioned information as well as your web-app requirement. </p><p>For instance, if you or your client needs a modern web application with definitive features in a quick time, then Django would be more suitable. If your requirement is for a highly customized website it is better to prefer Node.js.</p>]]></content:encoded></item><item><title><![CDATA[Beginner's Guide to Laravel Resources]]></title><description><![CDATA[In this tutorial, we'll learn what Laravel Resources are, and how to use them in our Laravel project.]]></description><link>https://blog.shahednasser.com/beginners-guide-to-laravel-resources/</link><guid isPermaLink="false">Ghost__Post__61542709ee4e50060ce9760c</guid><category><![CDATA[Laravel]]></category><category><![CDATA[Beginners]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 29 Sep 2021 10:15:25 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/53c28cfa5ff477e7df0bfc2414ae1303/dean-pugh-C8NDn4xk9zs-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/53c28cfa5ff477e7df0bfc2414ae1303/dean-pugh-C8NDn4xk9zs-unsplash-2.jpg" alt="Beginner's Guide to Laravel Resources"/><p>Laravel is a great framework that is popular among developers and is used for all kinds of projects. One of Laravel's usages is creating APIs.</p><p>One asset that you can use to make sure your APIs in Laravel are uniform across requests and the correct desired data is being returned in all APIs is <a href="https://laravel.com/docs/8.x/eloquent-resources">Laravel Resources</a>.</p><p>In this tutorial, we'll learn what Laravel Resources are, and how to use them in our Laravel project. You can find the code for this tutorial in <a href="https://github.com/shahednasser/laravel-resources-tutorial">this GitHub Repository</a>.</p><h3 id="what-are-laravel-resources">What are Laravel Resources</h3><p>Laravel Resources are another layer added on top of Laravel Eloquent models. It allows creating a uniform format or shapes for the data returned for these Eloquent models.</p><h3 id="why-use-laravel-resources">Why Use Laravel Resources</h3><p>It's important to make sure the correct data is being sent in your APIs. For example, you don't want to accidentally send secret data like keys or tokens related to users or other models in your APIs.</p><p>Furthermore, when building APIs, it's important that the structure of data is the same across requests. This also helps other developers that might be using your API, as it ensures the data structure across different requests.</p><h2 id="prerequisites">Prerequisites </h2><p>Before we see how we can use Resources in Laravel, we'll first undergo a few commands to set up our Laravel project. If you already have your project set up you can skip this step.</p><h3 id="create-laravel-project">Create Laravel Project</h3><p>In your terminal, run the following command to create a Laravel project with <a href="https://getcomposer.org">Composer</a>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">composer</span> create-project laravel/laravel laravel-resources</code></pre></div><p>After the command is done executing, change to the newly created project directory:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> laravel-resources</code></pre></div><h3 id="prepare-the-database">Prepare the Database</h3><p>Next, we'll set up the database. You'll need to make sure you have a <a href="https://dev.mysql.com/downloads/mysql/">MySQL server</a> installed if that's your choice of database.</p><h3 id="setup-database-and-connection">Setup Database and Connection</h3><p>We'll create a new database <code class="language-text">laravel-resources</code>. You can create a database of any name you want.</p><p>After you create the database, go to <code class="language-text">.env</code> and change the configurations related to the database connection:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel-resources DB_USERNAME=root DB_PASSWORD=</code></pre></div><p>Make sure to place your database name in <code class="language-text">DB_DATABASE</code>, database username in <code class="language-text">DB_USERNAME</code>, and database password in <code class="language-text">DB_PASSWORD</code>.</p><h3 id="changes-to-default-user-model">Changes to Default User Model</h3><p>In this tutorial, we'll make use of the default User model that comes with every Laravel project. However, we'll make a slight change by adding a new field <code class="language-text">age</code>.</p><p>First, we'll make changes to the <a href="https://laravel.com/docs/8.x/migrations">migration</a> file. If you're not sure what a migration is, database migrations in Laravel allow defining the database schema easily.</p><p>Open <code class="language-text">database/migrations/2014_10_12_000000_create_users_table.php</code> and add the following line inside <code class="language-text">Schema::create</code> callback function:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token variable">$table</span><span class="token operator">-></span><span class="token function">integer</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'age'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This will add a new <code class="language-text">age</code> field in the <code class="language-text">users</code> table.</p><p>Next, we'll modify the user <a href="https://laravel.com/docs/8.x/database-testing#creating-models-using-factories">factory</a> as we'll use it to create random users. If you're not sure what a factory is, Laravel provides a way to create database records for a model for testing.</p><p>Open <code class="language-text">database/factories/UserFactory.php</code> and inside the <code class="language-text">definition</code> function add the following at the end of the returned array:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token string single-quoted-string">'age'</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">faker</span><span class="token operator">-></span><span class="token function">numberBetween</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">90</span><span class="token punctuation">)</span></code></pre></div><p>So, the <code class="language-text">definition</code> function should look like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">definition</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'name'</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">faker</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'email'</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">faker</span><span class="token operator">-></span><span class="token function">unique</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">safeEmail</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'email_verified_at'</span> <span class="token operator">=></span> <span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'password'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi'</span><span class="token punctuation">,</span> <span class="token comment">// password</span> <span class="token string single-quoted-string">'remember_token'</span> <span class="token operator">=></span> <span class="token class-name static-context">Str</span><span class="token operator">::</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'age'</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">faker</span><span class="token operator">-></span><span class="token function">numberBetween</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">90</span><span class="token punctuation">)</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Finally, we'll make a change to the User model. Open <code class="language-text">app/Models/User.php</code> and add the <code class="language-text">age</code> field to the <code class="language-text">fillable</code> array:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">protected</span> <span class="token variable">$fillable</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'name'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'email'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'password'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'age'</span> <span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre></div><h3 id="create-database-tables">Create Database Tables</h3><p>We'll now create the database tables using Laravel's migrations. Run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php">php artisan migrate</code></pre></div><p>This will create the <code class="language-text">users</code> table as well as other tables that come by default in Laravel.</p><h3 id="add-fake-users">Add Fake Users</h3><p>Next, we'll utilize the UserFactory to create fake users in our database for testing. Go to <code class="language-text">database/seeders/DatabaseSeeder.php</code> and uncomment the following line:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token comment">// \App\Models\User::factory(10)->create();</span></code></pre></div><p>Then, run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan db:seed</code></pre></div><p>And with that, we'll have 10 fake users in our database.</p><h2 id="create-a-user-resource">Create a User Resource</h2><p>Resources are created on top of an eloquent model. This means that typically you'd need a resource for every eloquent model separately.</p><p>We'll create a resource for our User model, then see how we can use it in requests.</p><p>To create a resource, run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan make:resource UserResource</code></pre></div><p>This will create a new class <code class="language-text">UserResource</code> in <code class="language-text">app/Http/Resources</code>. This is where all Resources that you will create will reside in.</p><p>If you open <code class="language-text">UserResource</code> now, you'll see that there's already a <code class="language-text">toArray</code> method. This is the method that is used to return the data related to the user. By default, it just returns the result of <code class="language-text">toArray</code> method on the user.</p><p>The current model that the resource is being used for, in this case, it's a user model, is represented inside the resource class by the field <code class="language-text">resource</code> in the class. So, you can reference the underlying class with <code class="language-text">$this->resource</code>.</p><p>We'll change the returned array of <code class="language-text">toArray</code> in <code class="language-text">UserResource</code> to only return the user's id, name, and email. Change the content of <code class="language-text">toArray</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">return</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'id'</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">resource</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'name'</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">resource</span><span class="token operator">-></span><span class="token property">name</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'email'</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">resource</span><span class="token operator">-></span><span class="token property">email</span> <span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre></div><p>Remember, <code class="language-text">$this->resource</code> refers to an instance of the User model.</p><p>We've created our first resource! We'll see it in action in the next section.</p><h3 id="create-api-endpoint">Create API Endpoint</h3><p>In this section, we'll create an API endpoint that allows us to retrieve the data of any user using their ID.</p><p>First, we'll create a new controller <code class="language-text">UserController</code> to handle API requests related to the <code class="language-text">User</code> model. Run the following command in your terminal:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan make:controller UserController</code></pre></div><p>Then, go to <code class="language-text">app/Http/Controllers/UserController.php</code>. We'll create a new method <code class="language-text">getUser</code> that accepts an ID and should return the user's data. Add the following inside the <code class="language-text">UserController</code> class:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">getUser</span><span class="token punctuation">(</span><span class="token variable">$id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">find</span><span class="token punctuation">(</span><span class="token variable">$id</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'success'</span> <span class="token operator">=></span> <span class="token constant boolean">false</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'message'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'User does not exist'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'success'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'user'</span> <span class="token operator">=></span> <span class="token keyword">new</span> <span class="token class-name">UserResource</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>We first check that a user with that ID exists. If the user doesn't exist we return a JSON response with<code class="language-text">success</code> set to <code class="language-text">false</code> with a message indicating that the user does not exist.</p><p>If the user exists, we return a JSON response with <code class="language-text">success</code> set to <code class="language-text">true</code> and <code class="language-text">user</code> set to an instance of <code class="language-text">UserResource</code>.</p><p>Note that to create an instance of a resource, you need to pass it the model the resource should use as a parameter to the constructor like so:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">new</span> <span class="token function">UserResource</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span></code></pre></div><p>That's all we need to do! We just need to add the new API endpoint as a route.</p><p>Open <code class="language-text">routes/api.php</code> and add the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user/{id}'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">UserController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'getUser'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Our API is ready! Time to test it.</p><p>Start your server with the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan serve</code></pre></div><p>Then, to test the API endpoint you can use something like Postman or Thunder Client. As this is a GET request without authentication you can also just open the URLs in your browser.</p><p>Send a GET request to <code class="language-text">localhost:8000/api/user/1</code> or open the URL in your browser. You'll see that the endpoint will return a JSON response with 2 keys, <code class="language-text">success</code> and <code class="language-text">user</code>. Notice how the <code class="language-text">user</code> object includes just the user's <code class="language-text">id</code>, <code class="language-text">name</code>, and <code class="language-text">email</code> which is what we added in our UserResource.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-29-at-11.31.56-AM.png" class="kg-image" alt="Beginner's Guide to Laravel Resources" loading="lazy" width="2000" height="1432" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/Screen-Shot-2021-09-29-at-11.31.56-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/09/Screen-Shot-2021-09-29-at-11.31.56-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/09/Screen-Shot-2021-09-29-at-11.31.56-AM.png 1600w, https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-29-at-11.31.56-AM.png 2226w" sizes="(min-width: 720px) 720px"/></figure><p>You can try changing the <code class="language-text">id</code>, which is <code class="language-text">1</code> in the above request, to other IDs and see how it returns the same response structure for all users.</p><h2 id="create-a-user-collection-resource">Create a User Collection Resource</h2><p>Resources are not just for single model instances. You can create a collection resource that takes a collection of model instances as a parameter and formats the collection as necessary.</p><p>To create a collection resource for the User model run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan make:resource UserCollection --collection</code></pre></div><p>This will create the collection resource class at <code class="language-text">app/Http/Resources/UserCollection.php</code>.</p><p>Note that for collection resources there is a naming convention to make sure that the collection is associated with the correct resource model for the instance. The naming convention is <code class="language-text"><Model>Collection</code>.</p><p>So, since our resource name is model name is <code class="language-text">User</code> the collection resource name will be <code class="language-text">UserCollection</code>.</p><p>If you wish to name the collection differently, you can specify the resource class using the <code class="language-text">collects</code> field on the collection class:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token variable">$collects</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">;</span></code></pre></div><p>Collection resources are similar to singular resources. There is a <code class="language-text">toArray</code> method that we will use to define the structure of collections.</p><p>Change the content of <code class="language-text">toArray</code> method to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token variable">$count</span> <span class="token operator">=</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">collection</span><span class="token operator">-></span><span class="token function">count</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'count'</span> <span class="token operator">=></span> <span class="token variable">$count</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'data'</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">collection</span> <span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre></div><p>Note that <code class="language-text">$this->collection</code> will return an array of objects with the structure the same as defined in <code class="language-text">UserResource</code> for each user instance in the collection.</p><h3 id="create-api-endpoint-1">Create API Endpoint</h3><p>We'll now create an API endpoint that will allow us to get all users. In <code class="language-text">UserController</code> that we created previously add the following method:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">getUsers</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$users</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'success'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'users'</span> <span class="token operator">=></span> <span class="token keyword">new</span> <span class="token class-name">UserCollection</span><span class="token punctuation">(</span><span class="token variable">$users</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>To create an instance of the collection resource, similar to the singular resource, you need to pass the collection of models as a parameter to the constructor.</p><p>Then, add the new route in <code class="language-text">routes/api.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">UserController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'getUsers'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Let's test it. Send a GET request to <code class="language-text">localhost:8000/api/user</code> or open it in your browser. You'll see that it returns 2 keys <code class="language-text">success</code> and <code class="language-text">users</code>. <code class="language-text">users</code> will be an array of users and all having the same structure as that defined in <code class="language-text">UserResource</code>.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-29-at-11.39.18-AM.png" class="kg-image" alt="Beginner's Guide to Laravel Resources" loading="lazy" width="2000" height="1499" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/Screen-Shot-2021-09-29-at-11.39.18-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/09/Screen-Shot-2021-09-29-at-11.39.18-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/09/Screen-Shot-2021-09-29-at-11.39.18-AM.png 1600w, https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-29-at-11.39.18-AM.png 2226w" sizes="(min-width: 720px) 720px"/></figure><p>This shows an example of how defining a Resource guarantees the same structure across requests.</p><h2 id="conditional-fields">Conditional Fields</h2><p>Sometimes you might need to add a field based on a condition. To do so, you can use the <code class="language-text">when</code> method defined on resources.</p><p>We'll add an <code class="language-text">old</code> field that should appear only when the user's age is greater than <code class="language-text">18</code>. Add the following field in the returned array in <code class="language-text">toArray</code> in <code class="language-text">UserResource</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token string single-quoted-string">'old'</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">when</span><span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">resource</span><span class="token operator">-></span><span class="token property">age</span> <span class="token operator">></span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token constant boolean">true</span><span class="token punctuation">)</span></code></pre></div><p>This will add the <code class="language-text">old</code> field only if the user's age is greater than 18. Note that the first paramter of <code class="language-text">when</code> is the condition and the second parameter is the value expected.</p><p>Try sending a GET request to <code class="language-text">localhost:8000/api/user</code> or open the URL in your browser now. You'll see that some users will have the <code class="language-text">old</code> field while others don't.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-29-at-11.40.36-AM.png" class="kg-image" alt="Beginner's Guide to Laravel Resources" loading="lazy" width="2000" height="1496" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/Screen-Shot-2021-09-29-at-11.40.36-AM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/09/Screen-Shot-2021-09-29-at-11.40.36-AM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/09/Screen-Shot-2021-09-29-at-11.40.36-AM.png 1600w, https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-29-at-11.40.36-AM.png 2232w" sizes="(min-width: 720px) 720px"/></figure><p>Note that the result for your request will defer as the users generated by the factory are random.</p><h2 id="conclusion">Conclusion</h2><p>Laravel's API Resources allow making your returned data in APIs structured and uniform. It also guarantees what the fields returned will be so no fields will be accidentally exposed.</p><p>You can check out more details about Laravel Resources in <a href="https://laravel.com/docs/8.x/eloquent-resources#introduction">their documentation</a>.</p>]]></content:encoded></item><item><title><![CDATA[Major Mistakes to Avoid in College Assignments]]></title><description><![CDATA[To make their life easy, college students should pay attention to the following tips to avoid making common errors.]]></description><link>https://blog.shahednasser.com/major-mistakes-to-avoid-in-college-assignments/</link><guid isPermaLink="false">Ghost__Post__615413ddee4e50060ce975e3</guid><category><![CDATA[Education]]></category><dc:creator><![CDATA[Pratibha Singh]]></dc:creator><pubDate>Wed, 29 Sep 2021 07:27:54 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/c0c950602c86092b73e6e4d6f299c964/nick-morrison-FHnnjk1Yj7Y-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/c0c950602c86092b73e6e4d6f299c964/nick-morrison-FHnnjk1Yj7Y-unsplash-2.jpg" alt="Major Mistakes to Avoid in College Assignments"/><p>University students have a nightmare when they hear about assignments or projects as a task from their professors because they must exhibit their best to score good marks for those assignments. Some students who start to write their academic documents might be unaware of the mistakes (whether trivial or vital) that might delay their graduation or could cause them to lose marks or points in their assignments. Preparing an assignment requires in-depth research, expert consultation, deep learning. No wonder why assignments are seen as the toughest part of their college life.</p><p>To make their life easy, college students should pay attention to the following tips to avoid making the common errors:<br/></p><h2 id="insufficient-background-research">Insufficient background research</h2><p>The most common mistake university students make while writing assignments or essays is that they lack sufficient knowledge about the subject and miss doing proper research about the topic before writing about it. In addition to that, they also miss referring to the right sources to perform their research. The students should consult the librarian (in a library of course!!) or online academic resources to find the right content and coin it clearly in the essays or assignments to be presented at the university. This will help them to boost their performance and students will stand a good chance of scoring well. They should always give their full potential to understand the given topic by doing a lot of research on that topic.</p><h2 id="redundant-information"><br>Redundant Information</br></h2><p>Secondly, students should try to avoid presenting similar information repeatedly at different places in the written assignment. Students often repeat the same sentences in order to fill the assignment which might cost them a lot by losing precious marks. Some of them provide the same content in both Introduction & Conclusion segments which will make your assignment dull and boring. Hence, always try to fill in with lots and lots of information as possible, try to end the content with ideas, suggestions, add images, raise questions for the audience to think, and avoid redundant information in the document. Repetition of words, phrases & clauses shows that students are not in full understanding of the topic assigned. Students should always try their best to set the first impression on professors with their rich content and no redundant data.</p><h2 id="plagiarism">Plagiarism</h2><p>Another common mistake that often goes unnoticed by students is duplicate check tests run on assignments by professors. Students should avoid copying content from online websites or books as such and should try to be creative while writing assignments to score high marks. There are several plagiarism checkers online like Copyscape that can be used to ensure the written assignment is free of duplicate content. The plagiarism report shows the percentage of content that’s copied from other sources and not cited in the document. This report reveals that students have not done their basic research resulting in serious impacts and is considered an offense. Students should always avoid the following steps to overcome plagiarism:</p><ol><li>Avoid Copy-Pasting – Never copy and paste content from other’s works as it indicates that students have completed the assignment without spending much effort.</li><li>Missing Citations – Don’t miss adding citations in the written assignment.</li><li>Avoid Entire quotations – While copying sentences from other sources, add quotation marks with a citation to avoid plagiarism.</li><li>Get Permissions – In order to use a copyrighted study, get permission from the copyright holder.</li></ol><p>You can also get <a href="https://assignmentxp.com/">online assignment help</a> from the experts available at <a href="http://assignmentxp.com/">assignmentxp.com</a>, they can provide you plagiarism free perfect solutions to your problems.</p><h2 id="no-formatting-grammatical-mistakes">No Formatting & Grammatical Mistakes</h2><p>Students often ignore the importance of formatting the document which plays a major role in scoring high for assignments. They should always make sure that the document is properly aligned, titles are appropriately named, sentences are grammatically correct so that the document looks neat and readable for the reviewers. They should also concentrate on the tone which is to be always formal and avoid using informal pronouns as language reflects their personality. Sometimes students trying to elaborate a topic frames sentences so confusingly that it becomes unclear to the professors. Other than these mistakes, they also end doing a lot of spelling errors while writing assignments which must be given the utmost importance because that reflects one’s professional ability and skills. There are several online spell check websites like Grammarly.com that helps to do the corrections. Finally, ensure that the structure of the document is appropriate and narrates the story well. The structure of the document is very important because ordering the content helps in conveying the information clearly. Therefore, proper titles, related images, appropriate order completes an assignment.</p><h2 id="inadequate-citation-and-academic-referencing">Inadequate Citation and Academic Referencing</h2><p>Another mistake that students do is not consulting enough educational resources and references and improper use of citation which spoils their work. Academic referencing and citing means acknowledgment of sources used in the assignments. Citing a reference acknowledges the study students have referred to and allows professors to find the work that they have cited. Each source cited in the assignments has some implications. Academic referencing conveys that students are not the first ones to write on that topic and shows that they do use others’ ideas to create a new one. Thus, professors could track those references to get more ideas about a particular point they have made and also allows them to see how dated the information might be. Usage of words, facts, ideas, or explanations from other works should be cited. When students have copied texts from an essay, an article, a book, or other sources verbatim, which are called quotations, those must be academically referenced. One should do the referencing even if they use an idea or a fact from some other’s work or even if they haven’t used their exact expression. Only when the information is considered as common knowledge, it need not be cited.</p><p>Academic referencing projects students’ efforts and validates their work and hence it’s very important to provide sufficient citations and academic referencing in assignments.</p><p>So students and writers do keep in your mind the above-mentioned points to avoid while writing an essay or assignment or article. Happy writing!!</p>]]></content:encoded></item><item><title><![CDATA[React Native Tutorial: Create Your First App]]></title><description><![CDATA[In this tutorial, you'll learn the basics of creating a React Native app with Expo.]]></description><link>https://blog.shahednasser.com/react-native-tutorial-create-your-first-app/</link><guid isPermaLink="false">Ghost__Post__614f6edf9d27d705cce79807</guid><category><![CDATA[React Native]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 27 Sep 2021 14:22:06 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/9cf7bd6f419e5efbda67610c5d80d321/jonathan-kemper-t6Wmvbw_MdI-unsplash-2-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/9cf7bd6f419e5efbda67610c5d80d321/jonathan-kemper-t6Wmvbw_MdI-unsplash-2-2.jpg" alt="React Native Tutorial: Create Your First App"/><p><a href="https://reactnative.dev">React Native</a> is one of the most popular frameworks that allow you to create cross-platform apps using JavaScript. Using React Native, you'll be able to write one code for the web, iOS, and Android.</p><p>In this tutorial, you'll learn the basics of creating a React Native app with <a href="https://expo.dev">Expo</a>. We'll create a to-do list app where we'll learn about implementing navigation in a React Native app and storing data in our app.</p><p>You can find the code for this tutorial in <a href="https://github.com/shahednasser/react-native-tutorial">this GitHub Repository</a>. You can also <a href="https://expo.dev/@shahednasser/todolist">install the app</a> using Expo Go. There is more info on how to install Expo Go below.</p><h2 id="prerequisites">Prerequisites</h2><p>Before you start going through the tutorial, you'll need to install <a href="https://nodejs.org/en/">Node.js</a> which will install NPM with it.</p><p>You also need to install Expo. Expo provides a set of tools to make your mobile development with React Native easier. </p><p>To install Expo run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> -g expo-cli</code></pre></div><p>Finally, you'll need to install <a href="https://expo.dev/client">Expo Go</a> on your phone. It's available for both <a href="https://play.google.com/store/apps/details?id=host.exp.exponent&hl=en&gl=US">Android</a> and <a href="https://apps.apple.com/us/app/expo-go/id982107779">iOS</a>.</p><p>By installing Expo Go on your phone, you'll be able to test your app directly on your phone as you make changes. </p><h2 id="setup-project">Setup Project</h2><p>To create a new React Native project, run the following command in your terminal:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">expo init todolist</code></pre></div><p>You'll be asked to choose the kind of project you want to create, choose <code class="language-text">blank</code>.</p><p>After you choose <code class="language-text">blank</code>, the project will be set up and the minimal dependencies required to create an app with React Native will be installed.</p><p>After the setup is done, change to the directory of the project:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> todolist</code></pre></div><h2 id="project-structure">Project Structure</h2><p>Let's take a quick look at the project's structure before we start coding.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-25-at-9.56.47-PM.png" class="kg-image" alt="React Native Tutorial: Create Your First App" loading="lazy" width="548" height="578"/></figure><p>We have the usual <code class="language-text">package.json</code> files that you find in every NPM project.</p><p>There's <code class="language-text">app.json</code>. This includes a set of configurations for our app. If you open it, you'll find key-value pairs related to the app name, version, icon, splash screen, and more.</p><p><code class="language-text">App.js</code> is the entry point of our app. It's where we will start writing our app's code.</p><p>The <code class="language-text">assets</code> directory includes images like the app icon, splash screen, and more.</p><h3 id="understand-first-components-in-react-native">Understand First Components in React Native</h3><p>If you open <code class="language-text">App.js</code>, you'll find content similar to this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> StatusBar <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'expo-status-bar'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> StyleSheet<span class="token punctuation">,</span> Text<span class="token punctuation">,</span> View <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native'</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>View style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>container<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Text<span class="token operator">></span>Open up App<span class="token punctuation">.</span>js to start working on your app<span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>Text<span class="token operator">></span> <span class="token operator"><</span>StatusBar style<span class="token operator">=</span><span class="token string">"auto"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>View<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> styles <span class="token operator">=</span> StyleSheet<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">container</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">flex</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">backgroundColor</span><span class="token operator">:</span> <span class="token string">'#fff'</span><span class="token punctuation">,</span> <span class="token literal-property property">alignItems</span><span class="token operator">:</span> <span class="token string">'center'</span><span class="token punctuation">,</span> <span class="token literal-property property">justifyContent</span><span class="token operator">:</span> <span class="token string">'center'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre></div><p>This is our first component! As you can see, components like <code class="language-text">View</code>, <code class="language-text">Text</code> and others imported from <code class="language-text">react-native</code> are being used.</p><p>You should know that in React Native when displaying the text you need to do it inside a <code class="language-text">Text</code> component. </p><p>React Native provides a set of components that will be later transformed into native components in iOS or Android.</p><p>We also create stylesheets to add styling to our components using <code class="language-text">StyleSheet.create</code>, where <code class="language-text">StyleSheet</code> is imported from <code class="language-text">react-native</code> as well.</p><p>The <code class="language-text">create</code> method takes an object of properties, which act like class names in CSS, and their values are objects of CSS-like properties and their values. Styling your components in React Native is almost identical to styling using CSS, with a few changes in some behaviors of some CSS properties.</p><h2 id="screens-and-navigation">Screens and Navigation</h2><p>Now, we'll start adding screens to our app. To add different screens and manage navigation between them, we'll use <a href="https://reactnavigation.org/">React Navigation</a>.</p><p>For an elaborate tutorial on Navigation, check out my tutorial <a href="https://blog.shahednasser.com/react-native-navigation-tutorial/">React Native Navigation Tutorial</a>.</p><h3 id="home-screen">Home Screen</h3><p>Create the directories <code class="language-text">src/screens</code>. The <code class="language-text">screens</code> directory will hold all the screens we will create later on.</p><p>Then, create <code class="language-text">HomeScreen.js</code> inside <code class="language-text">screens</code>. This will be the first screen that the user will see when they open the app.</p><p>Add the following content inside <code class="language-text">HomeScreen.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Text<span class="token punctuation">,</span> View <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native'</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">HomeScreen</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>View<span class="token operator">></span> <span class="token operator"><</span>Text<span class="token operator">></span>Welcome Home<span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>Text<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>View<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>The home screen, at the moment, will just display the text "Welcome Home!".</p><h3 id="install-react-navigation">Install React Navigation</h3><p>Next, we'll see how to use multiple screens with React Navigation.</p><p>React Navigation allows us to move between screens backward and forwards, add buttons to the header, and more.</p><p>To install React Navigation, run the following commands:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> @react-navigation/native expo <span class="token function">install</span> react-native-screens react-native-safe-area-context <span class="token function">npm</span> <span class="token function">install</span> @react-navigation/native-stack</code></pre></div><p>Once these commands are done executing, we'll have all the dependencies required to use React Navigation.</p><h3 id="how-react-navigation-works">How React Navigation Works</h3><p>To put things simply, React Navigation manages screens, navigation between them, and history as a Stack. </p><p>There's a default, initial screen that shows when the app is launched. Then, when you want to open a new screen, you can push it at the top of the stack or replace the current item in the stack.</p><p>Then, when you want to go backward, you pop the current item at the top of the stack and show the one below it, which was the previous screen, until you reach the home, initial screen.</p><p> If it sounds confusing at the moment, keep going through in the tutorial and you'll start understanding things more.</p><h3 id="create-the-navigation-stack">Create the Navigation Stack</h3><p>Change the content of <code class="language-text">App.js</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token string">'react-native-gesture-handler'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> createStackNavigator <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@react-navigation/stack'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> NavigationContainer <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@react-navigation/native'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> HomeScreen <span class="token keyword">from</span> <span class="token string">'./src/screens/HomeScreen'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> Stack <span class="token operator">=</span> <span class="token function">createStackNavigator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>NavigationContainer<span class="token operator">></span> <span class="token operator"><</span>Stack<span class="token punctuation">.</span>Navigator initialRouteName<span class="token operator">=</span><span class="token string">"Home"</span><span class="token operator">></span> <span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Home"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>HomeScreen<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Stack<span class="token punctuation">.</span>Navigator<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>NavigationContainer<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre></div><p>Let's go over things bit by bit.</p><p>We first need to import <code class="language-text">react-native-gesture-handler</code> at the top of the app. This allows navigating using gestures. The higher in the app it's placed the better.</p><p>Next, we're importing <code class="language-text">createStackNavigator</code>. This function returns a Stack object, which contains two components <code class="language-text">Screen</code> and <code class="language-text">Navigator</code>. </p><p><code class="language-text">Screen</code> is used to display screen components that we create, define their options, and more. If you look at the example above, we provide a <code class="language-text">name</code> and <code class="language-text">component</code> props for a screen:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Home"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>HomeScreen<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>The <code class="language-text">name</code> prop can be used to navigate to that screen at any given point later. The <code class="language-text">component</code> prop will be used to define the screen component to render when the screen is navigated to.</p><p><code class="language-text">Navigator</code> should contain <code class="language-text">Screen</code> components as children as it manages the routing between them. <code class="language-text">Navigator</code> also receives the <code class="language-text">initialRouteName</code> prop which determines the screen that should open when the app first launches.</p><p>Finally, we use <code class="language-text">NavigationContainer</code> to wrap the <code class="language-text">Navigator</code> components, as it manages the navigation tree and state.</p><p>So, in <code class="language-text">App.js</code>, which will contain the navigation routes for the screens in the app as we go forward, we should render the <code class="language-text">NavigationContainer</code> and inside it <code class="language-text">Stack.Navigator</code> which contains one or more <code class="language-text">Stack.Screen</code> components:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>NavigationContainer<span class="token operator">></span> <span class="token operator"><</span>Stack<span class="token punctuation">.</span>Navigator initialRouteName<span class="token operator">=</span><span class="token string">"Home"</span><span class="token operator">></span> <span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Home"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>HomeScreen<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Stack<span class="token punctuation">.</span>Navigator<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>NavigationContainer<span class="token operator">></span></code></pre></div><h2 id="run-the-app">Run the App</h2><p>Let's run the app now. To do that, open the terminal and run the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>This will start Expo. As mentioned earlier, with Expo you will be able to run the app on your phone, so make sure you've installed Expo Go as detailed in the Prerequisites section.</p><p>A web page will open that looks something like this:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-26-at-3.16.27-PM.png" class="kg-image" alt="React Native Tutorial: Create Your First App" loading="lazy" width="2000" height="1172" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/Screen-Shot-2021-09-26-at-3.16.27-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/09/Screen-Shot-2021-09-26-at-3.16.27-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/09/Screen-Shot-2021-09-26-at-3.16.27-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/09/Screen-Shot-2021-09-26-at-3.16.27-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>There are multiple ways to run the app after this on your device. You can scan the QR code with your phone to open it in Expo Go. Alternatively, you can use one of the actions on the sidebar of the web page above like send link with email and so on.</p><p>Once you choose the best way to open the app on your phone and it opens, you should see the following screen:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/IMG_7813.PNG" class="kg-image" alt="React Native Tutorial: Create Your First App" loading="lazy" width="1242" height="2208" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/IMG_7813.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/09/IMG_7813.PNG 1000w, https://backend.shahednasser.com/content/images/2021/09/IMG_7813.PNG 1242w" sizes="(min-width: 720px) 720px"/></figure><p>We've run our first app! We'll start customizing the styles of the header next and add more screens to create a Todo List app.</p><h2 id="style-the-header">Style the Header</h2><p>With React Navigation, there are 2 ways to style the header of a screen.</p><h3 id="style-screen-headers-individually">Style Screen Headers Individually</h3><p>The first way is to style it for each screen. This can be done by passing the <code class="language-text">options</code> prop to a <code class="language-text">Screen</code> component like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Home"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>HomeScreen<span class="token punctuation">}</span> options<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">headerStyle</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">backgroundColor</span><span class="token operator">:</span> <span class="token string">'#228CDB'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">headerTintColor</span><span class="token operator">:</span> <span class="token string">'#fff'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>The <code class="language-text">options</code> prop is an object of options for the screen. To style the header, we can use the following three properties:</p><ol><li><code class="language-text">headerStyle</code>: accepts an object of styles to apply to the header. To set the background color of the header, we pass it the <code class="language-text">backgroundColor</code> prop with the value of the background color of the header.</li><li><code class="language-text">headerTintColor</code>: the color of the text or buttons that are in the header.</li><li><code class="language-text">headerTitleStyle</code>: accepts an object of font-related styles to make changes to the title in the header. For example, we can change the <code class="language-text">fontFamily</code> or <code class="language-text">fontWeight</code>.</li></ol><p>Using this prop, we'll be able to style the header of a screen.</p><h3 id="style-all-screen-headers">Style All Screen Headers</h3><p>In general cases, styling each screen separately is tedious and leads to repeated code. Usually, you'd apply the same header style to all screens in the app.</p><p>In this case, we can use the <code class="language-text">screenOptions</code> prop on the <code class="language-text">Navigator</code> component. This prop accepts the same header options as the <code class="language-text">options</code> prop in the <code class="language-text">Screen</code> component and applies the styling to all screens.</p><h3 id="apply-header-styles-in-our-app">Apply Header Styles in Our App</h3><p>In our app, we'll apply the same header style to all the screens in the app. So, we'll use the second way to style a header.</p><p>In App.js, replace this line:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Stack<span class="token punctuation">.</span>Navigator initialRouteName<span class="token operator">=</span><span class="token string">"Home"</span><span class="token operator">></span></code></pre></div><p>With the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Stack<span class="token punctuation">.</span>Navigator screenOptions<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">headerStyle</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">backgroundColor</span><span class="token operator">:</span> <span class="token string">'#228CDB'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">headerTintColor</span><span class="token operator">:</span> <span class="token string">'#fff'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> initialRouteName<span class="token operator">=</span><span class="token string">"Home"</span><span class="token operator">></span></code></pre></div><p>This will change the background color of the header to <code class="language-text">#228CDB</code> and the color of the text and buttons in the header to <code class="language-text">#fff</code>.</p><p>If you save the changes and open the app again, you'll see that the header color changed.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/IMG_7814.PNG" class="kg-image" alt="React Native Tutorial: Create Your First App" loading="lazy" width="1242" height="2208" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/IMG_7814.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/09/IMG_7814.PNG 1000w, https://backend.shahednasser.com/content/images/2021/09/IMG_7814.PNG 1242w" sizes="(min-width: 720px) 720px"/></figure><h2 id="navigate-screens">Navigate Screens</h2><p>Next, we'll see how to add another screen and navigate to it. We'll also see how to add a header button.</p><h3 id="add-new-screen">Add New Screen</h3><p>We'll add a new screen, which we'll use later to add a new to-do list item. </p><p>Create <code class="language-text">src/screens/NewScreen.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Text<span class="token punctuation">,</span> View <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native'</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">NewScreen</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>View<span class="token operator">></span> <span class="token operator"><</span>Text<span class="token operator">></span>This is New Screen<span class="token operator"><</span><span class="token operator">/</span>Text<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>View<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>Similar to <code class="language-text">HomeScreen</code>, we're just showing the text "This is New Screen" for now.</p><h3 id="add-route-for-new-screen">Add Route for New Screen</h3><p>Now, we need to add a new route in our navigation stack for the new route. In <code class="language-text">App.js</code> below the <code class="language-text">Screen</code> component for <code class="language-text">HomeScreen</code> add a new one for <code class="language-text">NewScreen</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"New"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>NewScreen<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><h3 id="add-header-button">Add Header Button</h3><p>Next, we'll add a header button on the Home screen. It will be a plus button that should take us to <code class="language-text">NewScreen</code>.</p><p>To add a button to the header of a screen, we do it using the <code class="language-text">headerRight</code> property of the <code class="language-text">options</code> prop passed to <code class="language-text">Screen</code>. The <code class="language-text">headerRight</code> property accepts a function that should return a component to render.</p><p>Instead of using React Native's <a href="https://reactnative.dev/docs/button">Button</a> component, we'll use <a href="https://reactnativeelements.com">React Native Elements</a>' <a href="https://reactnativeelements.com/docs/icon">Icon</a> component. Adding a plus icon looks better than an actual button.</p><p>So, let's first install React Native Elements in our project:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i react-native-elements</code></pre></div><p>Then, change the following line in <code class="language-text">App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Home"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>HomeScreen<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>to this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Home"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>HomeScreen<span class="token punctuation">}</span> options<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function-variable function">headerRight</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>Icon name<span class="token operator">=</span><span class="token string">"plus"</span> type<span class="token operator">=</span><span class="token string">"feather"</span> color<span class="token operator">=</span><span class="token string">"#fff"</span> style<span class="token operator">=</span><span class="token punctuation">{</span>style<span class="token punctuation">.</span>headerIcon<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>As you can see, we are using the Icon component, passing it the prop <code class="language-text">name</code> which is the name of the icon to be used. <code class="language-text">type</code> as React Native Elements allow us to choose from multiple icon sets. We are using <a href="https://feathericons.com">Feather</a> icons. <code class="language-text">color</code> indicates the color of the icon. And finally, we're passing it <code class="language-text">style</code>. Add the following to the end of <code class="language-text">App.js</code> to create a new stylesheet:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> style <span class="token operator">=</span> StyleSheet<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">headerIcon</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">marginRight</span><span class="token operator">:</span> <span class="token number">10</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This will add a margin-right to the icon, as it won't have any by default.</p><p>If you run the app now, you'll see that a new + icon has been added to the header but it does nothing at the moment.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/IMG_7817.PNG" class="kg-image" alt="React Native Tutorial: Create Your First App" loading="lazy" width="1242" height="2208" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/IMG_7817.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/09/IMG_7817.PNG 1000w, https://backend.shahednasser.com/content/images/2021/09/IMG_7817.PNG 1242w" sizes="(min-width: 720px) 720px"/></figure><h3 id="navigating-to-another-screen">Navigating to Another Screen</h3><p>We need to navigate to <code class="language-text">NewScreen</code> when the plus icon is pressed.</p><p>In React Native, button's press events are handled by passing a listener in the <code class="language-text">onPress</code> prop of the button. So, we'll need to pass a handler for <code class="language-text">onPress</code> to <code class="language-text">Icon</code>.</p><p>To navigate to another screen, we can use the <code class="language-text">navigation</code> prop. The <code class="language-text">navigation</code> prop is passed to every screen in the stack navigation. </p><p>Another way we can use the <code class="language-text">navigation</code> prop is by changing the value that the <code class="language-text">options</code> prop accepts of a <code class="language-text">Screen</code> to a function. The function accepts as a parameter an object which contains <code class="language-text">navigation</code>, and the function should return an object of options.</p><p>Then, using the <code class="language-text">navigation</code> prop we can navigate to another screen with the <code class="language-text">navigate</code> method:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">navigation<span class="token punctuation">.</span><span class="token function">navigate</span><span class="token punctuation">(</span><span class="token string">'New'</span><span class="token punctuation">)</span></code></pre></div><p>Where <code class="language-text">navigate</code> accepts the name of the screen we're navigating to.</p><p>So, change the line for <code class="language-text">HomeScreen</code> in <code class="language-text">App.js</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Stack<span class="token punctuation">.</span>Screen name<span class="token operator">=</span><span class="token string">"Home"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>HomeScreen<span class="token punctuation">}</span> options<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>navigation<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token function-variable function">headerRight</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>Icon name<span class="token operator">=</span><span class="token string">"plus"</span> type<span class="token operator">=</span><span class="token string">"feather"</span> color<span class="token operator">=</span><span class="token string">"#fff"</span> style<span class="token operator">=</span><span class="token punctuation">{</span>style<span class="token punctuation">.</span>headerIcon<span class="token punctuation">}</span> onPress<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> navigation<span class="token punctuation">.</span><span class="token function">navigate</span><span class="token punctuation">(</span><span class="token string">'New'</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>If you open the app now and click on the plus icon, you'll be taken to <code class="language-text">NewScreen</code>.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/IMG_7818.PNG" class="kg-image" alt="React Native Tutorial: Create Your First App" loading="lazy" width="1242" height="2208" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/IMG_7818.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/09/IMG_7818.PNG 1000w, https://backend.shahednasser.com/content/images/2021/09/IMG_7818.PNG 1242w" sizes="(min-width: 720px) 720px"/></figure><p>You can also see that, by default, a back button is added to the header and you can use it to go backward in the navigation stack. If you click on it, you'll go back to the Home screen.</p><h2 id="new-todo-item-form">New Todo Item Form</h2><p>Next, we'll add a form to add a new todo item in <code class="language-text">NewScreen</code>. To simplify creating a form, we'll use <a href="https://formik.org">Formik</a>.</p><p>If you're not familiar with Formik, it's a React and React Native library that aims to simplify the process of creating a form.</p><p>To install Formik, run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> formik --save</code></pre></div><p>Then, change the content of <code class="language-text">src/screens/NewScreen.js</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> Formik <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'formik'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> StyleSheet<span class="token punctuation">,</span> View <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Text <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-elements'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-elements/dist/buttons/Button'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Input <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-elements/dist/input/Input'</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">NewScreen</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">function</span> <span class="token function">newTask</span> <span class="token punctuation">(</span><span class="token parameter">values</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//TODO save new task</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Formik initialValues<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">}</span><span class="token punctuation">}</span> onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>newTask<span class="token punctuation">}</span> <span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>handleChange<span class="token punctuation">,</span> handleBlur<span class="token punctuation">,</span> handleSubmit<span class="token punctuation">,</span> values<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>View style<span class="token operator">=</span><span class="token punctuation">{</span>style<span class="token punctuation">.</span>container<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Text h4<span class="token operator">></span>New Todo Item<span class="token operator"><</span><span class="token operator">/</span>Text<span class="token operator">></span> <span class="token operator"><</span>Input placeholder<span class="token operator">=</span><span class="token string">"Example: Cook, Clean, etc..."</span> onChangeText<span class="token operator">=</span><span class="token punctuation">{</span><span class="token function">handleChange</span><span class="token punctuation">(</span><span class="token string">'title'</span><span class="token punctuation">)</span><span class="token punctuation">}</span> onBlur<span class="token operator">=</span><span class="token punctuation">{</span><span class="token function">handleBlur</span><span class="token punctuation">(</span><span class="token string">'title'</span><span class="token punctuation">)</span><span class="token punctuation">}</span> style<span class="token operator">=</span><span class="token punctuation">{</span>style<span class="token punctuation">.</span>input<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Button title<span class="token operator">=</span><span class="token string">"Add"</span> onPress<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span> style<span class="token operator">=</span><span class="token punctuation">{</span>style<span class="token punctuation">.</span>button<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>View<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Formik<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> style <span class="token operator">=</span> StyleSheet<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">container</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">marginTop</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token literal-property property">padding</span><span class="token operator">:</span> <span class="token number">10</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">input</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">marginTop</span><span class="token operator">:</span> <span class="token number">10</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">button</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">backgroundColor</span><span class="token operator">:</span> <span class="token string">'#228CDB'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Let's go over everything we just added. We first define a new function <code class="language-text">newTask</code> inside the component, which we'll use later to handle saving a new task.</p><p>Then, we're creating a form with Formik. In Formik, you can use the <code class="language-text">Formik</code> component and pass it <code class="language-text">initialValues</code> to define the fields and their initial values. We just have one field <code class="language-text">title</code> and its initial value is just an empty string.</p><p>We also pass the <code class="language-text">Formik</code> component an <code class="language-text">onSubmit</code> prop which is the function that should be executed when the form is submitted. We're passing it <code class="language-text">newTask</code>.</p><p>Inside the <code class="language-text">Formik</code> component, you use a function that has a set of parameters but most importantly are <code class="language-text">handleChange</code>, <code class="language-text">handleBlur</code>, <code class="language-text">handleSubmit</code>, and <code class="language-text">values</code>. The function should return a component to render.</p><p>If you're familiar with Formik when using it with React, you'll notice that this is slightly different than how you'd use it with React. As inputs in React Native are not similar to inputs on the web since they don't have names, you need to clearly specify for each input the <code class="language-text">onChange</code> and <code class="language-text">onBlur</code> listeners passing them the name of the input.</p><p>So, for the title <a href="https://reactnativeelements.com/docs/input">Input</a>, which is a component we are using from React Native Elements, we pass for <code class="language-text">onChange</code> the listener <code class="language-text">handleChange('title')</code> and for <code class="language-text">onBlur</code> the listener <code class="language-text">handleBlur('title')</code>.</p><p>Then, we add a <a href="https://reactnativeelements.com/docs/button">Button</a> component, which is another component we are using from React Native Elements. We assign the listener for <code class="language-text">onPress</code> on the button to <code class="language-text">handleSubmit</code>. This means that when the button is pressed, the submit event will be triggered in the form, which will trigger <code class="language-text">newTask</code> since we assigned it as the listener to <code class="language-text">onSubmit</code>.</p><p>Notice that we are adding some styling to the screen and components in it. We use the <code class="language-text">styles</code> variable which is created with <code class="language-text">StyleSheet.create</code>, and we pass to each component a style prop with its value a property in the <code class="language-text">styles</code> variable. For example in <code class="language-text">View</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>View style<span class="token operator">=</span><span class="token punctuation">{</span>style<span class="token punctuation">.</span>container<span class="token punctuation">}</span><span class="token operator">></span></code></pre></div><p>If you open the app now, click on the plus button in the Home Screen which will open <code class="language-text">NewScreen</code>. You should see the form we just created.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/IMG_7819.PNG" class="kg-image" alt="React Native Tutorial: Create Your First App" loading="lazy" width="1242" height="2208" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/IMG_7819.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/09/IMG_7819.PNG 1000w, https://backend.shahednasser.com/content/images/2021/09/IMG_7819.PNG 1242w" sizes="(min-width: 720px) 720px"/></figure><h3 id="handle-submit">Handle Submit</h3><p>We'll now handle the submission of the form in the function <code class="language-text">newTask</code>. What we'll do is take the title and store it in the app.</p><p>There are many ways you can manage storage in React Native. We'll use <a href="https://react-native-async-storage.github.io/async-storage/">Async Storage</a>. It provides a simple API to store data in your app. For data that are not too complex, like settings related to the user or app, it's a great choice.</p><p>We'll use Async Storage to store the todo list items in our app. So, let's first install it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">expo <span class="token function">install</span> @react-native-async-storage/async-storage</code></pre></div><p>AsyncStorage has 2 functions in its API. getItem and setItem. using setItem, you set items serialized as strings. So, if you have an array or object you need to stringify them with <code class="language-text">JSON.stringify</code>. Then, you can retrieve the item with <code class="language-text">getItem</code> and you'll have to parse the JSON if it's stringified with <code class="language-text">JSON.parse</code>.</p><p>Add the following import at the beginning of <code class="language-text">NewScreen.js</code> along with the rest of the imports added before:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useAsyncStorage <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@react-native-async-storage/async-storage'</span><span class="token punctuation">;</span></code></pre></div><p>Then, inside the <code class="language-text">NewScreen</code> component, add the following line:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> getItem<span class="token punctuation">,</span> setItem <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useAsyncStorage</span><span class="token punctuation">(</span><span class="token string">'todo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>We are using the <a href="https://react-native-async-storage.github.io/async-storage/docs/api#useasyncstorage">useAsyncStorage</a> hook which allows us to pass the name of a key in the storage and retrieve a getter <code class="language-text">getItem</code> and a setter <code class="language-text">setItem</code> solely for that key in the storage.</p><p>Before we start implementing the functionality inside <code class="language-text">newTask</code>, we need 2 other dependencies: <a href="https://www.npmjs.com/package/react-native-uuid">react-native-uuid</a> to generate random IDs for every task in storage, and <a href="https://www.npmjs.com/package/react-native-toast-message">react-native-toast-message</a> to show toast messages if an error occurs:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i react-native-uuid react-native-toast-message</code></pre></div><p>For react-native-toast-message to work, we first need to add a <code class="language-text">Toast</code> component in one of the higher components rendered in the App. So, add the following line in <code class="language-text">App.js</code> before the closing of <code class="language-text">NavigationContainer</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"> <span class="token operator"><</span>Toast ref<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">ref</span><span class="token punctuation">)</span> <span class="token operator">=></span> Toast<span class="token punctuation">.</span><span class="token function">setRef</span><span class="token punctuation">(</span>ref<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>NavigationContainer<span class="token operator">></span></code></pre></div><p>And, of course, add the necessary import at the beginning of <code class="language-text">App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Toast <span class="token keyword">from</span> <span class="token string">'react-native-toast-message'</span><span class="token punctuation">;</span></code></pre></div><p>Back to <code class="language-text">NewScreen.js</code>. We'll now implement <code class="language-text">newTask</code>. We'll first validate that the user entered a value for <code class="language-text">title</code>. Then, we'll get the <code class="language-text">todo</code> items from the storage, which will be an array of objects where each object is a to-do item. Then, we'll push a new item into the array and set the item in storage again.</p><p>Change the <code class="language-text">newTask</code> function to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">newTask</span> <span class="token punctuation">(</span><span class="token parameter">values</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>values<span class="token punctuation">.</span>title<span class="token punctuation">)</span> <span class="token punctuation">{</span> Toast<span class="token punctuation">.</span><span class="token function">show</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'error'</span><span class="token punctuation">,</span> <span class="token literal-property property">text1</span><span class="token operator">:</span> <span class="token string">'Title is required'</span><span class="token punctuation">,</span> <span class="token literal-property property">position</span><span class="token operator">:</span> <span class="token string">'top'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//get todo array from storage</span> <span class="token function">getItem</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">todoJSON</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">let</span> todo <span class="token operator">=</span> todoJSON <span class="token operator">?</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>todoJSON<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">//add a new item to the list</span> todo<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> uuid<span class="token punctuation">.</span><span class="token function">v4</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">title</span><span class="token operator">:</span> values<span class="token punctuation">.</span>title <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//set item in storage again</span> <span class="token function">setItem</span><span class="token punctuation">(</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//navigate back to home screen</span> navigation<span class="token punctuation">.</span><span class="token function">goBack</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span> Toast<span class="token punctuation">.</span><span class="token function">show</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'error'</span><span class="token punctuation">,</span> <span class="token literal-property property">text1</span><span class="token operator">:</span> <span class="token string">'An error occurred and a new item could not be saved'</span><span class="token punctuation">,</span> <span class="token literal-property property">position</span><span class="token operator">:</span> <span class="token string">'top'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span> Toast<span class="token punctuation">.</span><span class="token function">show</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'error'</span><span class="token punctuation">,</span> <span class="token literal-property property">text1</span><span class="token operator">:</span> <span class="token string">'An error occurred and a new item could not be saved'</span><span class="token punctuation">,</span> <span class="token literal-property property">position</span><span class="token operator">:</span> <span class="token string">'bottom'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>As you can see, we're checking first if <code class="language-text">values.title</code> has been entered. If not, we show a toast message and return. To show a toast message using react-native-toast-message you need to pass it an object of options. There are a variety of options you can use, but the most important here are <code class="language-text">type</code> which can be <code class="language-text">error</code>, <code class="language-text">success</code>, or <code class="language-text">info</code>, <code class="language-text">position</code> which can be <code class="language-text">top</code> or <code class="language-text">bottom</code>, and <code class="language-text">text1</code> which will be the message to show in the toast.</p><p>After validating <code class="language-text">title</code>, we then use <code class="language-text">getItem</code> to retrieve <code class="language-text">todo</code> from the storage if it exists. <code class="language-text">getItem</code> returns a Promise as it is asynchronous, and the value of <code class="language-text">todo</code> is passed to <code class="language-text">then</code> function handler.</p><p>Inside <code class="language-text">then</code> we parse the JSON, then push a new to-do item. Each todo item will have an <code class="language-text">id</code> which is randomly generated, and a <code class="language-text">title</code>.</p><p>Finally, we set the <code class="language-text">todo</code> array in the storage again as JSON. Once it is set successfully, we navigate back to the Home screen with <code class="language-text">navigation.goBack</code>. As we mentioned earlier, all items in the navigation stack receive <code class="language-text">navigation</code> as a prop. So, make sure to add the prop for <code class="language-text">NewScreen</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">NewScreen</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> navigation <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span></code></pre></div><p>You can now try the form. Open the app and go to the <code class="language-text">NewScreen</code>. Try first to submit the form without entering a title. You should see then a message telling you that the Title is required.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/IMG_7841.PNG" class="kg-image" alt="React Native Tutorial: Create Your First App" loading="lazy" width="1242" height="2208" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/IMG_7841.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/09/IMG_7841.PNG 1000w, https://backend.shahednasser.com/content/images/2021/09/IMG_7841.PNG 1242w" sizes="(min-width: 720px) 720px"/></figure><p>Now try to enter a title and press "Add". You'll be navigated back to the Home Screen. That means that the item was added successfully!</p><p>What's left for us to do is display them on the Home Screen.</p><h3 id="display-tasks">Display Tasks</h3><p>We'll now change the content of the Home Screen to display the todo list items we are adding in <code class="language-text">NewScreen</code>.</p><p>To do so, we'll use the same function we used in <code class="language-text">NewScreen</code> from Async Storage to get the items. To display the items, we'll use <a href="https://reactnative.dev/docs/flatlist">FlatList</a>, a component that allows us to display a list of items easily.</p><p>Change the content of <code class="language-text">HomeScreen</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useAsyncStorage <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@react-native-async-storage/async-storage'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useEffect<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> FlatList<span class="token punctuation">,</span> StyleSheet<span class="token punctuation">,</span> Text<span class="token punctuation">,</span> View <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Card <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native-elements'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Toast <span class="token keyword">from</span> <span class="token string">'react-native-toast-message'</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">HomeScreen</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> navigation <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> getItem <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useAsyncStorage</span><span class="token punctuation">(</span><span class="token string">'todo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>items<span class="token punctuation">,</span> setItems<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>loading<span class="token punctuation">,</span> setLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">getTodoList</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">getItem</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">todoJSON</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> todo <span class="token operator">=</span> todoJSON <span class="token operator">?</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>todoJSON<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token function">setItems</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span> Toast<span class="token punctuation">.</span><span class="token function">show</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'error'</span><span class="token punctuation">,</span> <span class="token literal-property property">text1</span><span class="token operator">:</span> <span class="token string">'An error occurred'</span><span class="token punctuation">,</span> <span class="token literal-property property">position</span><span class="token operator">:</span> <span class="token string">'top'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">renderCard</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>item<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Card<span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Title style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>cardTitle<span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{</span>item<span class="token punctuation">.</span>title<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>Card<span class="token punctuation">.</span>Title<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> unsubscribe <span class="token operator">=</span> navigation<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token string">'focus'</span><span class="token punctuation">,</span> getTodoList<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> unsubscribe<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>View<span class="token operator">></span> <span class="token operator"><</span>FlatList refreshing<span class="token operator">=</span><span class="token punctuation">{</span>loading<span class="token punctuation">}</span> onRefresh<span class="token operator">=</span><span class="token punctuation">{</span>getTodoList<span class="token punctuation">}</span> style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>list<span class="token punctuation">}</span> data<span class="token operator">=</span><span class="token punctuation">{</span>items<span class="token punctuation">}</span> renderItem<span class="token operator">=</span><span class="token punctuation">{</span>renderCard<span class="token punctuation">}</span> keyExtractor<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> item<span class="token punctuation">.</span>id<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>View<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> styles <span class="token operator">=</span> StyleSheet<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">list</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'100%'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">cardTitle</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">textAlign</span><span class="token operator">:</span> <span class="token string">'left'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Here's a breakdown of what this code is doing. First, we're using <code class="language-text">useAsyncStorage</code> hook just like we did before to get a getter function for <code class="language-text">todo</code>. We're also creating state variables <code class="language-text">items</code> and <code class="language-text">loading</code>. <code class="language-text">items</code> will be used to store the items after fetching them from the storage. <code class="language-text">loading</code> will be used to indicate that we're currently retrieving the items from the storage.</p><p>Then, we create the function <code class="language-text">getTodoList</code>. This function should be executed every time the screen is opened. In this function, we're just using the getter function <code class="language-text">getItem</code> like we did before and once we retrieve the todo list items from the storage, we're setting the state <code class="language-text">items</code> and <code class="language-text">loading</code>.</p><p>After that, we create the function <code class="language-text">renderCard</code>. This function will be used to render each item in the FlatList. We'll be using the <a href="https://reactnativeelements.com/docs/card">Card</a> component from React Native Element to display them.</p><p>Next is the important part. In <code class="language-text">useEffect</code>, we are adding an event listener to the <code class="language-text">focus</code> event for the <code class="language-text">navigator</code> object that the screens inside the navigation stack receive as a prop. The focus event is triggered every time the screen comes into focus. So, this listener for the focus event will run when the app launch and the Home screen is shown, and when we go back from the <code class="language-text">NewScreen</code> to the Home screen.</p><p>Finally, we're displaying the <code class="language-text">FlatList</code> component. It receives the <code class="language-text">refreshing</code> prop which indicates whether the list is currently refreshing. We're passing it the <code class="language-text">loading</code> state. We're also passing it an event handler for the refresh event in the prop <code class="language-text">onRefresh</code>. This event is triggered whenever the user refreshes the list by pulling it down.</p><p>The <code class="language-text">data</code> prop indicates the data that we're displaying in the list and should be an array. The <code class="language-text">renderItem</code> prop receives a function to render each item, and that function will be passed an object which includes the <code class="language-text">item</code> property, indicating the current item to be rendered in the list. </p><p>The <code class="language-text">keyExtractor</code> prop indicates how to assign the <code class="language-text">key</code> prop for each item in the list. In React and React Native, when rendering an array of items you should pass a key <code class="language-text">prop</code> to each item. We're setting the key for each item its id.</p><p>In the end, we're defining the stylesheet to style all elements.</p><p> If you open the app now, you'll see that on the Home Screen a list of items will appear which are items that you add in the <code class="language-text">NewScreen</code>. Try going to the <code class="language-text">NewScreen</code> again and adding more items. You'll see them added to the list.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/IMG_7843.PNG" class="kg-image" alt="React Native Tutorial: Create Your First App" loading="lazy" width="1242" height="2208" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/IMG_7843.PNG 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/09/IMG_7843.PNG 1000w, https://backend.shahednasser.com/content/images/2021/09/IMG_7843.PNG 1242w" sizes="(min-width: 720px) 720px"/></figure><h2 id="publish-the-app">Publish the App</h2><p>The last step that comes when creating an app is to publish it. React Native's documentation has a guide on how to publish your app on <a href="https://reactnative.dev/docs/signed-apk-android">Google Play Store</a> and <a href="https://reactnative.dev/docs/publishing-to-app-store">Apple App Store</a>.</p><p>If, however, you want to publish the app but you don't have a developer account for either Google or Apple, you can publish the <a href="https://docs.expo.dev/workflow/publishing/">app on Expo</a>, but that would require anyone to install Expo to be able to try or use your app.</p><h2 id="conclusion">Conclusion</h2><p>You just created your first app! You were able to create an app with navigation, forms, storage, lists, and more!</p><p>If you want to keep practicing, try adding a delete or edit functionality. Make sure to check more of React Native's <a href="https://reactnative.dev">documentation</a> as well as React Navigation's documentation on <a href="https://reactnavigation.org/docs/params">how to pass parameters</a> as well.</p>]]></content:encoded></item><item><title><![CDATA[How to Use Confirm Dialogs in JavaScript]]></title><description><![CDATA[In this tutorial, we'll learn how to use confirm() and how to show confirmation dialog before the user leaves the page.]]></description><link>https://blog.shahednasser.com/how-to-use-confirm-dialogs-in-javascript/</link><guid isPermaLink="false">Ghost__Post__614322b39d27d705cce7971a</guid><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 20 Sep 2021 10:29:11 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/45864775af44ab395b289aebfc2365f4/Confirm.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/45864775af44ab395b289aebfc2365f4/Confirm.png" alt="How to Use Confirm Dialogs in JavaScript"/><p>You've probably seen the confirm dialog being used whenever you're making edits to data on a website. Whether you're filling out a form, editing a document, or just making any kind of changes that require you to save your progress, you'll probably see an alert when you try to leave the page to alert you that your progress will not be saved if you leave.</p><p>The confirm dialog is a simple yet necessary user experience strategy that shows your users that you understand them. </p><p>In this tutorial, we'll learn how to use the <code class="language-text">confirm</code> function to confirm a user's actions. We'll also see how to show a confirm dialog before the user leaves the page based on whether the user saved their progress or not.</p><h2 id="use-confirm">Use confirm()</h2><p>If you want to show a dialog that confirms the user's actions at any point, you can use <code class="language-text">window.confirm</code>. </p><p>This function accepts one optional parameter, which is the message to show to the user. If the parameter is not provided, no message will be shown. Then, it returns a boolean based on what the user chooses. If the user "OK", it returns true, else it returns false.</p><p>For example, we'll show a button that will trigger the confirm dialog on click:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>confirmTrigger<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Show Confirm<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>confirmResult<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span></code></pre></div><p>Inside <code class="language-text">p</code> we'll show the result based on what the user chooses.</p><p>Then, in our JavaScript we'll add an event listener to the button's click event:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'confirmTrigger'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> confirmResult <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'confirmResult'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> button<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>window<span class="token punctuation">.</span><span class="token function">confirm</span><span class="token punctuation">(</span><span class="token string">'Do you confirm?'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> confirmResult<span class="token punctuation">.</span>innerText <span class="token operator">=</span> <span class="token string">'Yes'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> confirmResult<span class="token punctuation">.</span>innerText <span class="token operator">=</span> <span class="token string">'No'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This will show a confirm dialog with the text "Do you confirm?".</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-16-at-2.33.03-PM.png" class="kg-image" alt="How to Use Confirm Dialogs in JavaScript" loading="lazy" width="1052" height="338" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/Screen-Shot-2021-09-16-at-2.33.03-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/09/Screen-Shot-2021-09-16-at-2.33.03-PM.png 1000w, https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-16-at-2.33.03-PM.png 1052w" sizes="(min-width: 720px) 720px"/></figure><p>If the user presses OK, "Yes" will be displayed in the <code class="language-text">p</code> element.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-16-at-2.33.08-PM.png" class="kg-image" alt="How to Use Confirm Dialogs in JavaScript" loading="lazy" width="232" height="156"/></figure><p>Else, "No" will be displayed in the <code class="language-text">p</code> element:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-16-at-2.33.17-PM.png" class="kg-image" alt="How to Use Confirm Dialogs in JavaScript" loading="lazy" width="222" height="146"/></figure><p>That's it! Using <code class="language-text">window.confirm</code>, you can confirm a user's actions at any given point on your website.</p><h2 id="show-a-confirm-dialog-when-a-user-leaves-a-page">Show a Confirm Dialog When a User Leaves a Page</h2><p>The most famous usage for confirm dialogs would be to warn the user before they leave or refresh the page, usually because they haven't saved their progress.</p><p>To implement this, you don't need to use <code class="language-text">confirm()</code>. You need to add a listener to the window's <code class="language-text">beforeunload</code> event.</p><h3 id="add-onbeforeunload-listener">Add onbeforeunload Listener</h3><p>To add a listener to the <code class="language-text">beforeunload</code> event, you can either assign a function to <code class="language-text">window.onbeforeunload</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">window<span class="token punctuation">.</span><span class="token function-variable function">onbeforeunload</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//do something</span> <span class="token punctuation">}</span></code></pre></div><p>or using <code class="language-text">window.addEventListener</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'beforeunload'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//do something</span> <span class="token punctuation">}</span></code></pre></div><p>Although this is <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload#example">the recommended method</a>, it seems that <code class="language-text">onbeforeunload</code> works and is supported more.</p><h3 id="show-a-confirm-dialog-before-leaving-the-page">Show a Confirm Dialog Before Leaving the Page</h3><p>To show the confirmation dialog before the user leaves the page, the event listener for <code class="language-text">beforeunload</code> the event should return a non-empty string. </p><p>If the listener does not return any value or returns an empty string, no confirm dialog will be shown to the user.</p><h3 id="when-the-confirm-dialog-is-not-shown">When the Confirm Dialog is Not Shown</h3><p>To avoid unwanted pop-ups, browsers generally will not display the confirm dialog on <code class="language-text">beforeunload</code> if the user has not interacted with the page.</p><p>For example, let's say we have the following page:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>IE=edge<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Confirm Dialog<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> window<span class="token punctuation">.</span><span class="token function-variable function">onbeforeunload</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">'Are you sure?'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre></div><p>This page has no elements (or any elements, actually) that the user can interact with, yet it requests to show a confirm dialog when the user leaves the page.</p><p>If you test this code on any modern browser, you'll see that the confirm dialog will not be shown.</p><h3 id="example"> Example</h3><p>We'll see how to show a confirm dialog only when the user hasn't saved their progress.</p><p>First, we'll show a text input so the user enters their name. We'll also show a button for them to save, and a <code class="language-text">p</code> element where we'll show the value they entered when they save:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Hello there!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>name<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Name<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span><span class="token punctuation">></span></span>Save<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span></code></pre></div><p>Then, in JavaScript, we'll first declare variables for each of these elements:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> input <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'input'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> p <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> saved <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></code></pre></div><p>Note that we also declared the variable <code class="language-text">saved</code>, initially set to <code class="language-text">false</code>. In a real use-case scenario, you'll probably manage whether the user saved their progress by checking if the data they entered has been saved on the server. To simplify the tutorial, we're just using this variable to manage whether the progress has been saved or not.</p><p>We'll add an event listener to <code class="language-text">button</code>'s click event. In this event listener, we'll change <code class="language-text">saved</code> to <code class="language-text">true</code>, and we'll change the text of <code class="language-text">p</code> to the value of <code class="language-text">input</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">button<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> p<span class="token punctuation">.</span>innerText <span class="token operator">=</span> input<span class="token punctuation">.</span>value<span class="token punctuation">;</span> saved <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> input<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>We'll also add an event listener to the <code class="language-text">input</code>'s <code class="language-text">keypress</code> event to change <code class="language-text">saved</code> to false when the user makes changes to the <code class="language-text">input</code>, even if they already saved their progress previously:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">input<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'keypress'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> saved <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Finally, we'll add the event listener for <code class="language-text">onbeforeunload</code>, which will show the confirmation dialog if the user has not saved their progress:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">window<span class="token punctuation">.</span><span class="token function-variable function">onbeforeunload</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>saved<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">'Are you sure?'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div><p>Note that although we return a string, this string will not actually be shown a custom message to the user. Custom messages <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload#browser_compatibility">used to be supported</a> in Chrome until version 51, Firefox until version 44, Safari until version 9, but is still supported in IE.</p><p>Let's try our example. First, open this page. You'll see a heading, input, and a button.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-16-at-3.09.40-PM.png" class="kg-image" alt="How to Use Confirm Dialogs in JavaScript" loading="lazy" width="502" height="282"/></figure><p>Let's first try leaving the page before interacting with any of the input elements. According to our code, if <code class="language-text">saved</code> is false, which is its initial value, the confirm dialog should show.</p><p>However, if you try leaving the page before interacting with the elements, you'll see that the confirm dialog will not show as explained before.</p><p>Now, try to make type something into the input, and before clicking Save, exit, or refresh the page. Then, a confirmation dialog will show to warn you before you leave the page:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-16-at-2.29.08-PM.png" class="kg-image" alt="How to Use Confirm Dialogs in JavaScript" loading="lazy" width="630" height="570" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/Screen-Shot-2021-09-16-at-2.29.08-PM.png 600w, https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-16-at-2.29.08-PM.png 630w"/></figure><p>If you try to enter in the input, click save, then leave the page, the confirm dialog will not show.</p><p>If you try to enter a value in the input, click save, then try to enter a value in the input again, you'll see that the confirmation dialog will be shown again.</p><p>With this example, we're able to manage the saved state and warn the user before leaving the page without saving their progress.</p><h2 id="conclusion">Conclusion</h2><p>As users may not be aware sometimes that they need to save their progress, or because they can make mistakes, it's important to show them a confirm dialog before they leave the page.</p><p>Using the <code class="language-text">beforeunload</code> event facilitates showing the confirm dialog before the user leaves or reloads the page. To show the confirm dialog at any other point, you can use <code class="language-text">confirm()</code> instead.</p>]]></content:encoded></item><item><title><![CDATA[How to Participate in Hacktoberfest 2021]]></title><description><![CDATA[Through Hacktoberfest, both developers and open-source projects benefit a lot.]]></description><link>https://blog.shahednasser.com/how-to-participate-in-hacktoberfest-2021/</link><guid isPermaLink="false">Ghost__Post__613f26ec6ed8e505e7f20b35</guid><category><![CDATA[Hacktoberfest]]></category><category><![CDATA[Beginners]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 16 Sep 2021 12:51:53 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/655b1af732c0a4614cc06ec18c247937/Copy-of-Beginner-s-Guide-to-Magento-2.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/655b1af732c0a4614cc06ec18c247937/Copy-of-Beginner-s-Guide-to-Magento-2.png" alt="How to Participate in Hacktoberfest 2021"/><p><a href="https://hacktoberfest.digitalocean.com/">Hacktoberfest</a> is an annual event hosted by <a href="https://www.digitalocean.com/">DigitalOcean</a> that aims to encourage developers to contribute to open-source projects and give back to the community.</p><p>Through this event, many developers gain the confidence to be part of the open-source community, and open-source projects and organizations benefit by getting the help to grow their projects.</p><p>In this article, I'll help you understand what Hacktoberfest is, why you should participate as a maintainer of an open-source software and as a participant who wants to contribute, how you should choose a project to contribute to if you're a participant, and how to prepare your repository to be part of Hacktoberfest and receive contributions.</p><p><em>Suggested Read: <a href="https://blog.shahednasser.com/how-i-learned-about-contributing-to-open-source-projects-by-creating-one/">How I Learned About Contributing to Open Source Projects By Creating One</a>.</em></p><h2 id="what-is-hacktoberfest">What is Hacktoberfest</h2><p>Every October, <a href="https://hacktoberfest.digitalocean.com">over 100k participants</a> from all over the world participate in Hacktoberfest by going on <a href="https://github.com/">GitHub</a>, choosing a repository, and contributing to it.</p><p>Contributions are done by submitting a pull request (PR) to any repository that is participating in Hacktoberfest. Once your pull request is deemed accepted (we'll go over how that works in the next sections), it will count into your participation in Hacktoberfest.</p><p>To successfully participate in Hacktoberfest, you will need to submit at least 4 accepted pull requests to any repositories that are participating in Hacktoberfest.</p><p>Once Hacktoberfest is over, which is at the end of October, the first 55,000 participants to have submitted at least 4 accepted pull requests will receive a t-shirt with a swag pack. And, starting this year, maintainers will be able to receive swag packs as well!</p><h2 id="why-participate-in-hacktoberfest">Why Participate in Hacktoberfest</h2><p>Although receiving a free t-shirt is always cool, there are more important reasons to participate in Hacktoberfest. Whether you are a maintainer or a participant, you will surely learn and benefit a lot from Hacktoberfest.</p><h3 id="as-a-maintainer">As a Maintainer</h3><p>As a repository maintainer, Hacktoberfest allows you to grow your community. By participating in Hacktoberfest, your repository will receive more traffic from developers who are looking to participate. </p><p>So, even when Hacktoberfest ends, if these developers liked the experience of contributing to your repository, they will come back to help with more issues.</p><p>Managing an open-source project can be hard, especially since you might lack the time to improve and expand on the project as a maintainer. So, Hacktoberfest is a great time to receive help on issues that have been pending for a while or enhancements that can be done to improve your project.</p><h3 id="as-a-participant">As a Participant</h3><p>Whether you're a beginner or not, there's always room for learning and expanding your knowledge. One of the best ways to do that is by contributing to open-source projects. </p><p>Open-source projects usually provide tools, libraries, or other types of resourceful services for the community for free. Contributing to them and helping them to keep going is helpful for the community, and ultimately for yourself.</p><p>As each project is different, each might rely on different programming languages, frameworks, tools, or other types of resources they use or provide. By contributing to them, you'll take the time to check how it works, what they use, and so on. You also take the time to solve a problem or an issue in the project or bring new enhancements to the table.</p><p>So, when you contribute you're also taking on new challenges to solve, which is a great way to learn and practice your skills.</p><p>If you're a beginner, by participating in Hacktoberfest, you can finally get over any fear you might have that is stopping you from contributing to open source projects. It was through Hacktoberfest that I finally started my journey in contributing to open source projects.</p><p><em>Suggested Read: <a href="https://blog.shahednasser.com/tips-for-beginners-to-open-source">Tips For Beginners to Open Source</a>.</em></p><h2 id="how-to-participate-in-hacktoberfest-as-a-maintainer">How to Participate in Hacktoberfest As a Maintainer</h2><p><em>Suggested Read: <a href="https://blog.shahednasser.com/tips-for-beginner-maintainers-of-open-source-projects/">Tips For Beginner Maintainers of Open Source Projects</a>.</em></p><p>As a maintainer, you need to do the following to make sure your repository is participating in Hacktoberfest:</p><ol><li>Add the <code class="language-text">hacktoberfest</code> label to your repository.</li><li>Add the <code class="language-text">Hacktoberfest</code> label to issues so that participants can know which issues they can work on. This is also helpful if you want to attract participants to simpler issues that they can start with.</li><li>Add contributing guidelines to your repository in <code class="language-text">CONTRIBUTING.md</code>. This is necessary to make sure that participants know how to contribute to your codebase. It saves both your time and theirs and ensures the commit history and code base stays clean and based on your project's conventions.</li></ol><h3 id="new-this-year-participate-as-a-maintainer">New This Year: Participate As a Maintainer</h3><p>This year, Hacktoberfest will not only reward participants who have submitted at least 4 pull requests, but also maintainers! </p><p>Starting this year, you can register for Hacktoberfest as a maintainer. Then, you'll need to complete at least 4 or more actions related to pull requests in participating repositories. These actions can be:</p><ol><li>Merging the pull request.</li><li>Approving a pull request review.</li><li>Adding the <code class="language-text">hacktober-fest</code> label to a pull request.</li><li>Adding an <code class="language-text">invalid</code> or <code class="language-text">spam</code> labels to a pull request.</li></ol><p>Once you perform some of these actions at least 4 times, and if you are one of the first 10k maintainers to perform these actions, you will receive a swag pack the same one that participants will receive!</p><h3 id="how-to-accept-participants">How to Accept Participants</h3><p>Participants will participate by sending pull requests to fix issues in your repositories. A participant's pull request is considered accepted for Hacktoberfest if it's merged, if it has passed approval by reviewers or if it has the label <code class="language-text">hacktoberfest-accepted</code>. So, if you accept a participant's pull request, but you're unable to merge it before October ends, or you appreciate the work they put in but for some reason, you can't merge the request, you can add the label to the pull request, and it will count into their participation in Hacktoberfest</p><h3 id="how-to-reject-participants-or-stop-spam">How to Reject Participants or Stop Spam</h3><p>Unfortunately, so many participants use this event just to get the swag kit and don't actually care about helping open-source projects. So, you are bound to receive some useless pull requests that do not fix any issue, and some might even cause problems.</p><p>These pull requests can be time-wasting for you, and it would definitely suck for them to count to their participation in Hacktoberfest. So, it's encouraged to use the labels <code class="language-text">spam</code> or <code class="language-text">invalid</code> on any pull request that should not be accepted and should be considered spam.</p><h3 id="recommendations">Recommendations</h3><p>As I mentioned earlier, Hacktoberfest can be very beneficial for both participants and maintainers. However, it's especially beneficial for beginner contributors to open source software. Hacktoberfest encourages them to start contributing if they haven't already.</p><p>As taking the first step is difficult, it's our job as maintainers to make it easier for them to contribute. This can be done by creating some simple and easy-to-fix issues. Try to also use labels in your repository that implies an issue is meant for beginners like <code class="language-text">first-timers-only</code>.</p><p>Also, make sure your contributing guidelines are straight and to the point. Unless your repository is strictly aimed at experienced and high-level contributors, you should try to simplify the guidelines to make sure they're understandable even for beginners. If not the entire thing, then maybe dedicate a section for complete beginners.</p><p>Finally, GitHub has introduced Discussions in the past year to repositories. It helps exchange ideas ask questions and more. You can promote in your README, your website, or any channel fitting for your project that contributors can use discussions if they need any help or want to suggest certain ideas. Take the time to help them and build your project's community.</p><h2 id="how-to-participate-in-hacktoberfest-as-a-participant">How to Participate in Hacktoberfest as a Participant</h2><p><em>Suggested Read: <a href="https://blog.shahednasser.com/tips-for-beginners-to-open-source">Tips For Beginners to Open Source</a>.</em></p><p>Participating in Hacktoberfest is easy. Here are the steps you should take to start participating:</p><ol><li>Find repositories that have "opted-in" to Hacktoberfest. This means repositories that have <a href="https://github.com/topics/hacktoberfest">the "hacktoberfest" label</a>.</li><li>In these repositories, look through their <em>Issues </em>tab. You should try to specifically find issues with the <code class="language-text">hacktoberfest</code> label, as maintainers will ensure to use that label with any issue they think would be best for Hacktoberfest participants. However, you can still choose any issue you think is fitting and you can contribute to.</li><li>Before working on any issue, make sure to comment on it and that you get assigned to the issue. This saves time for you and the maintainer and avoids any misunderstandings that might happen.</li><li>Once you are assigned the issue, make sure to read the contributing guidelines which are found in any repository in <code class="language-text">CONTRIBUTING.md</code>. These guidelines usually include details about the code base, how to contribute to different parts of the project, what you should or shouldn't do, and more.</li><li>If after the contributing guidelines you still are confused about certain details, you shouldn't hesitate to ask the repository maintainers questions. You can do that either by commenting on the issue or using the <em>Discussion </em>tab that should be part of the repository.</li><li>Once all is clear, fork the repository, create a new branch, perform the task you've been assigned, and when you're finally done submit a pull request with all the details required based on the repository you are contributing to.</li><li>If the time is running low on your pull request, meaning that your pull request was submitted at the end of October and the maintainers are not able to merge it any time soon, request from the maintainers that they add the <code class="language-text">hacktoberfest-accepted</code> label to your pull request. That way, it will still be counted into your participation.</li></ol><p>These are the steps required of you to participate in Hacktoberfest. Even if you're a beginner, if you try you'll see it's not so hard!</p><h3 id="dos">Do's</h3><p>As a participant, here are a list of things you are encouraged to do:</p><ol><li>Pick projects that either will actually benefit from your contributions or you will learn something from the contribution. Unfortunately, with the start of Hacktoberfest, a lot of repositories are created just to get attention. Contributing to them is easy, sure, but it doesn't actually benefit the open-source community or, ultimatly, you. Choose a project wisely.</li><li>Be respectful and patient when contributing to any repository. Although this should apply all year round and not just during Hacktoberfest, it's essential to remember in Hacktoberfest. Most repositories get 10x more traffic, contributions, issues and pull requests in Hacktoberfest. So, the maintainers are almost always in over their heads with the amount of reviews they have to provide and keep up with. So, respect the repository's rules and maintainers and be patient if it takes time for your pull requests to be reviewed or for you to get assigned an issue.</li><li>Keep contributing even after Hacktoberfest. Hacktoberfest encourages you to remember to contribute to open source projects, but it shouldn't be just this month. Take the time every now and then to contribute to these projects and help the community.</li></ol><h3 id="donts">Don't's</h3><p>As a participant, here's a list of things you shouldn't do:</p><ol><li>Don't send in useless pull requests. For example, I had a lot of participants contributing by sending pull requests that just adds a line in a file, or adds a comment for the sake of adding something. This is a waste of time, counterproductive and is the entire opposite of what Hacktoberfest is about.</li><li>Don't overstep your boundaries. If an issue is not assigned to you, do not send in a pull request to solve it anyway. Most repositories and projects have a certain workflow to manage issues and pull requests, and this can cause a mess. Check before working on an issue if someone is working on it.</li></ol><h2 id="some-respositories-to-start-with">Some Respositories to Start With</h2><p>You can consider this a self-promoting section, but I personally maintain a few open-source projects and we're always looking for help or enhancements to them! A lot of these projects have easy issues you can contribute to, so please take the time to look at them and consider them for your Hacktoberfest participation!</p><ol><li><a href="https://github.com/sButtons/sbuttons">sButtons</a>: <em>Simple buttons you can use easily for your next project.</em> In this project, we have issues regarding bug fixes, and we also accept ideas and implementations for new buttons.</li><li><a href="https://github.com/shahednasser/awesome-resources">Awesome Resources</a>: <em>List of helpful resources added by the community for the community! </em>This repository includes all helpful links about many topics that can be added by anyone. You can create a new topic to add a resource under, or add to existing ones. It's one of the easy repositories to contribute to but can also help a lot benefit from them.</li><li><a href="https://github.com/shahednasser/cross-post">Cross Post</a>: <em>Cross Post a blog to multiple websites. </em>This Node.js tool allows you to cross-post articles to DEV.to, Hashnode, and Medium. <em>Suggested Read: <a href="https://blog.shahednasser.com/i-created-a-cli-to-cross-post-your-articles-on-dev-hashnode-and-medium">I Created a CLI to Cross-Post Your Articles On Dev, Hashnode, and Medium</a>.</em></li></ol><h2 id="conclusion">Conclusion</h2><p>There are many open-source projects that are looking for your support and contributions, and what a better time to do that other than Hacktoberfest! Make sure to get your list of projects ready to contribute to them and give back to the community.</p>]]></content:encoded></item><item><title><![CDATA[How to Use Google Charts in React]]></title><description><![CDATA[In this tutorial, we'll see how to use Google Charts in React by creating a simple React app with Create React App (CRA) either with hooks or context.]]></description><link>https://blog.shahednasser.com/how-to-use-google-charts-in-react/</link><guid isPermaLink="false">Ghost__Post__613b4060d8016c9d86b2385b</guid><category><![CDATA[React]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 13 Sep 2021 07:10:56 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/5385eed3bb88c35f9384be4c0f1e2e0f/lukas-blazek-mcSDtbWXUZU-unsplash-2-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/5385eed3bb88c35f9384be4c0f1e2e0f/lukas-blazek-mcSDtbWXUZU-unsplash-2-1.jpg" alt="How to Use Google Charts in React"/><p><a href="https://developers.google.com/chart">Google Charts</a> is a free Javascript library that allows you to visualize data in many types of charts and graphs. It's very useful and easy to use in your projects.</p><p>In this tutorial, we'll see how to use Google Charts in React by creating a simple React app with <a href="https://create-react-app.dev">Create React App</a> (CRA). We'll learn how to use Google Charts with either hooks or context for different use cases.</p><p>You can check the code for this tutorial on <a href="https://github.com/shahednasser/react-google-charts-tutorial">this GitHub Repository</a>.</p><h2 id="create-react-app">Create React App</h2><p>We'll start by creating the React app. Run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-react-app react-google-charts</code></pre></div><p>After the command is done, we'll have a react website created with CRA.</p><p>We'll also install <a href="https://react-bootstrap.github.io">react-bootstrap</a> to use some helpful Bootstrap components:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">npm install react<span class="token operator">-</span>bootstrap@next bootstrap@<span class="token number">5.1</span><span class="token number">.0</span></code></pre></div><h2 id="using-google-charts-with-hooks">Using Google Charts With Hooks</h2><p>The first approach we'll check is how to use Google Charts in React with Hooks. The code for this section of the tutorial in the GitHub Repository is under <code class="language-text">src/WithHooks</code>.</p><h3 id="creating-the-hook">Creating the Hook</h3><p>Create the file <code class="language-text">src/useGoogleCharts.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useEffect<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">useGoogleCharts</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>google<span class="token punctuation">,</span> setGoogle<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>google<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//TODO load google charts</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>google<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> google<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> useGoogleCharts<span class="token punctuation">;</span></code></pre></div><p>This creates a new hook that has a state <code class="language-text">google</code>. This state allows us to check if Google Charts is loaded or not and it will hold the loaded <code class="language-text">window.google</code> object. Then, we will use <code class="language-text">useEffect</code> to load the charts when they're not loaded. Finally, we just return <code class="language-text">google</code>.</p><p>In order to load Google Charts, we need to load the script <code class="language-text">https://www.gstatic.com/charts/loader.js</code> in the <code class="language-text"><head></code> of the document, then when it's loaded, we'll load the core package of Google charts. Finally, when the core package is loaded, we'll set <code class="language-text">google</code> to <code class="language-text">window.google</code>.</p><p>Add the following code inside the <code class="language-text">if</code> condition:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> head <span class="token operator">=</span> document<span class="token punctuation">.</span>head<span class="token punctuation">;</span> <span class="token keyword">let</span> script <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'googleChartsScript'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>script<span class="token punctuation">)</span> <span class="token punctuation">{</span> script <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'script'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> script<span class="token punctuation">.</span>src <span class="token operator">=</span> <span class="token string">'https://www.gstatic.com/charts/loader.js'</span><span class="token punctuation">;</span> script<span class="token punctuation">.</span>id <span class="token operator">=</span> <span class="token string">'googleChartsScript'</span><span class="token punctuation">;</span> script<span class="token punctuation">.</span><span class="token function-variable function">onload</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>window<span class="token punctuation">.</span>google <span class="token operator">&&</span> window<span class="token punctuation">.</span>google<span class="token punctuation">.</span>charts<span class="token punctuation">)</span> <span class="token punctuation">{</span> window<span class="token punctuation">.</span>google<span class="token punctuation">.</span>charts<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span><span class="token string">'current'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token string-property property">'packages'</span><span class="token operator">:</span><span class="token punctuation">[</span><span class="token string">'corechart'</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> window<span class="token punctuation">.</span>google<span class="token punctuation">.</span>charts<span class="token punctuation">.</span><span class="token function">setOnLoadCallback</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setGoogle</span><span class="token punctuation">(</span>window<span class="token punctuation">.</span>google<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> head<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>script<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>window<span class="token punctuation">.</span>google <span class="token operator">&&</span> window<span class="token punctuation">.</span>google<span class="token punctuation">.</span>charts <span class="token operator">&&</span> window<span class="token punctuation">.</span>google<span class="token punctuation">.</span>visualization<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setGoogle</span><span class="token punctuation">(</span>window<span class="token punctuation">.</span>google<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>We're first checking if the script is already loaded to avoid loading it again.</p><p>If the script isn't loaded, we're creating the <code class="language-text">script</code> element, and we're adding an event listener for <code class="language-text">onload</code> that will load the code packages of Google Charts.</p><p>Then, when the packages are loaded we can set <code class="language-text">google</code> with <code class="language-text">setGoogle(window.google)</code>.</p><p>In case the script has already been loaded, we check if <code class="language-text">window.google</code> is set then set <code class="language-text">google</code>.</p><p>Finally, we'll return in <code class="language-text">useEffect</code> the following function:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">let</span> script <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'googleChartsScript'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>script<span class="token punctuation">)</span> <span class="token punctuation">{</span> script<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>This removes the script on unmount.</p><h3 id="creating-the-chart-component">Creating the Chart Component</h3><p>Next, we'll create the chart component that will draw the chart after the Google Chart library has been loaded. </p><p>Create the component <code class="language-text">src/PizzaChart.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useEffect<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Spinner <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">PizzaChart</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>google<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>chart<span class="token punctuation">,</span> setChart<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>google <span class="token operator">&&</span> <span class="token operator">!</span>chart<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//TODO draw the chart</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>loaded<span class="token punctuation">,</span> chart<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token operator">!</span>google <span class="token operator">&&</span> <span class="token operator"><</span>Spinner <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator"><</span>div id<span class="token operator">=</span><span class="token string">"pizzaChart"</span> className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token operator">!</span>google <span class="token operator">?</span> <span class="token string">'d-none'</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> PizzaChart<span class="token punctuation">;</span></code></pre></div><p>This component receives a <code class="language-text">google</code> prop, which will be the returned value from <code class="language-text">useGoogleCharts</code>. It has a <code class="language-text">chart</code> state to ensure that the chart is created only once. </p><p>Inside <code class="language-text">useEffect</code>, we'll check if <code class="language-text">google</code> is not null and if <code class="language-text">chart</code> is null. In that case, we'll draw the chart.</p><p>Finally, we're just showing a spinner if <code class="language-text">google</code> is null and we're creating the <code class="language-text">div</code> element that the chart will go into.</p><p>Back to the if condition in <code class="language-text">useEffect</code>, we need to add the code to draw the chart. We'll add the code from the <a href="https://developers.google.com/chart/interactive/docs/quick_start">Google Charts' Pie Chart Example</a>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token comment">// Create the data table.</span> <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">google<span class="token punctuation">.</span>visualization<span class="token punctuation">.</span>DataTable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> data<span class="token punctuation">.</span><span class="token function">addColumn</span><span class="token punctuation">(</span><span class="token string">'string'</span><span class="token punctuation">,</span> <span class="token string">'Topping'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> data<span class="token punctuation">.</span><span class="token function">addColumn</span><span class="token punctuation">(</span><span class="token string">'number'</span><span class="token punctuation">,</span> <span class="token string">'Slices'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> data<span class="token punctuation">.</span><span class="token function">addRows</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token punctuation">[</span><span class="token string">'Mushrooms'</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Onions'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Olives'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Zucchini'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Pepperoni'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Set chart options</span> <span class="token keyword">var</span> options <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string-property property">'title'</span><span class="token operator">:</span><span class="token string">'How Much Pizza I Ate Last Night'</span><span class="token punctuation">,</span> <span class="token string-property property">'width'</span><span class="token operator">:</span><span class="token number">400</span><span class="token punctuation">,</span> <span class="token string-property property">'height'</span><span class="token operator">:</span><span class="token number">300</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Instantiate and draw our chart, passing in some options.</span> <span class="token keyword">const</span> newChart <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">google<span class="token punctuation">.</span>visualization<span class="token punctuation">.</span>PieChart</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'pizzaChart'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> newChart<span class="token punctuation">.</span><span class="token function">draw</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setChart</span><span class="token punctuation">(</span>newChart<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>We're first collecting the data with the options, then we're using <code class="language-text">google.visualization</code> to draw the pie chart. Finally, we set the <code class="language-text">chart</code> state.</p><p>Inside <code class="language-text">src/App.js</code>, replace the content with the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> Container <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> PizzaChart <span class="token keyword">from</span> <span class="token string">"./PizzaChart"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> useGoogleCharts <span class="token keyword">from</span> <span class="token string">'./useGoogleCharts'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> google <span class="token operator">=</span> <span class="token function">useGoogleCharts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token operator"><</span>Container className<span class="token operator">=</span><span class="token string">"mt-3"</span><span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span>With Hooks<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>PizzaChart google<span class="token operator">=</span><span class="token punctuation">{</span>google<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span> </code></pre></div><p>Try running the server now if it isn't running. You'll see a pie chart.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-10-at-3.11.28-PM.png" class="kg-image" alt="How to Use Google Charts in React" loading="lazy" width="658" height="500" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/Screen-Shot-2021-09-10-at-3.11.28-PM.png 600w, https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-10-at-3.11.28-PM.png 658w"/></figure><h3 id="multiple-charts">Multiple Charts</h3><p>Let's try adding another chart. We'll create a new chart component <code class="language-text">src/DinosaurChart</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useEffect<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Spinner <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">DinosaurChart</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>google<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>chart<span class="token punctuation">,</span> setChart<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>google <span class="token operator">&&</span> <span class="token operator">!</span>chart<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> data <span class="token operator">=</span> google<span class="token punctuation">.</span>visualization<span class="token punctuation">.</span><span class="token function">arrayToDataTable</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token punctuation">[</span><span class="token string">'Dinosaur'</span><span class="token punctuation">,</span> <span class="token string">'Length'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Acrocanthosaurus (top-spined lizard)'</span><span class="token punctuation">,</span> <span class="token number">12.2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Albertosaurus (Alberta lizard)'</span><span class="token punctuation">,</span> <span class="token number">9.1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Allosaurus (other lizard)'</span><span class="token punctuation">,</span> <span class="token number">12.2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Apatosaurus (deceptive lizard)'</span><span class="token punctuation">,</span> <span class="token number">22.9</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Archaeopteryx (ancient wing)'</span><span class="token punctuation">,</span> <span class="token number">0.9</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Argentinosaurus (Argentina lizard)'</span><span class="token punctuation">,</span> <span class="token number">36.6</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Baryonyx (heavy claws)'</span><span class="token punctuation">,</span> <span class="token number">9.1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Brachiosaurus (arm lizard)'</span><span class="token punctuation">,</span> <span class="token number">30.5</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Ceratosaurus (horned lizard)'</span><span class="token punctuation">,</span> <span class="token number">6.1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Coelophysis (hollow form)'</span><span class="token punctuation">,</span> <span class="token number">2.7</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Compsognathus (elegant jaw)'</span><span class="token punctuation">,</span> <span class="token number">0.9</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Deinonychus (terrible claw)'</span><span class="token punctuation">,</span> <span class="token number">2.7</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Diplodocus (double beam)'</span><span class="token punctuation">,</span> <span class="token number">27.1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Dromicelomimus (emu mimic)'</span><span class="token punctuation">,</span> <span class="token number">3.4</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Gallimimus (fowl mimic)'</span><span class="token punctuation">,</span> <span class="token number">5.5</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Mamenchisaurus (Mamenchi lizard)'</span><span class="token punctuation">,</span> <span class="token number">21.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Megalosaurus (big lizard)'</span><span class="token punctuation">,</span> <span class="token number">7.9</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Microvenator (small hunter)'</span><span class="token punctuation">,</span> <span class="token number">1.2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Ornithomimus (bird mimic)'</span><span class="token punctuation">,</span> <span class="token number">4.6</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Oviraptor (egg robber)'</span><span class="token punctuation">,</span> <span class="token number">1.5</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Plateosaurus (flat lizard)'</span><span class="token punctuation">,</span> <span class="token number">7.9</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Sauronithoides (narrow-clawed lizard)'</span><span class="token punctuation">,</span> <span class="token number">2.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Seismosaurus (tremor lizard)'</span><span class="token punctuation">,</span> <span class="token number">45.7</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Spinosaurus (spiny lizard)'</span><span class="token punctuation">,</span> <span class="token number">12.2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Supersaurus (super lizard)'</span><span class="token punctuation">,</span> <span class="token number">30.5</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Tyrannosaurus (tyrant lizard)'</span><span class="token punctuation">,</span> <span class="token number">15.2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Ultrasaurus (ultra lizard)'</span><span class="token punctuation">,</span> <span class="token number">30.5</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Velociraptor (swift robber)'</span><span class="token punctuation">,</span> <span class="token number">1.8</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> options <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Lengths of dinosaurs, in meters'</span><span class="token punctuation">,</span> <span class="token literal-property property">legend</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">position</span><span class="token operator">:</span> <span class="token string">'none'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Instantiate and draw our chart, passing in some options.</span> <span class="token keyword">const</span> newChart <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">google<span class="token punctuation">.</span>visualization<span class="token punctuation">.</span>Histogram</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'dinosaurChart'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> newChart<span class="token punctuation">.</span><span class="token function">draw</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setChart</span><span class="token punctuation">(</span>newChart<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>google<span class="token punctuation">,</span> chart<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token operator">!</span>google <span class="token operator">&&</span> <span class="token operator"><</span>Spinner <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator"><</span>div id<span class="token operator">=</span><span class="token string">"dinosaurChart"</span> className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token operator">!</span>google <span class="token operator">?</span> <span class="token string">'d-none'</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> DinosaurChart<span class="token punctuation">;</span></code></pre></div><p>This chart component is exactly similar to <code class="language-text">PizzaChart</code>, except it draws a Histogram rather than a Pie Chart. The code for the data is taken from Google Charts' Histogram Example.</p><p>Now, add the new component after <code class="language-text">PizzaChart</code> in <code class="language-text">src/App.js</code> in the returned JSX:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>PizzaChart google<span class="token operator">=</span><span class="token punctuation">{</span>google<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>DinosaurChart google<span class="token operator">=</span><span class="token punctuation">{</span>google<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>If you open the page now, you'll see two charts.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-10-at-3.39.38-PM.png" class="kg-image" alt="How to Use Google Charts in React" loading="lazy" width="2000" height="882" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/09/Screen-Shot-2021-09-10-at-3.39.38-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/09/Screen-Shot-2021-09-10-at-3.39.38-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/09/Screen-Shot-2021-09-10-at-3.39.38-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/09/Screen-Shot-2021-09-10-at-3.39.38-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><h2 id="using-google-charts-with-context">Using Google Charts With Context</h2><p>You can also use Google Charts with React Contexts. This allows you to use the <code class="language-text">google</code> object in any component without having to call the hook in one component and pass the <code class="language-text">google</code> object as a prop to the chart components.</p><p>The code for this section is found in the GitHub Repository in the directory <code class="language-text">src/WithContext</code>.</p><h3 id="create-google-context">Create Google Context</h3><p>First, create <code class="language-text">src/GoogleContext.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> React<span class="token punctuation">.</span><span class="token function">createContext</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">google</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token function-variable function">setGoogle</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This will create the Google Context with the <code class="language-text">google</code> object, initially null, and a setter function <code class="language-text">setGoogle</code>.</p><h3 id="use-context-provider">Use Context Provider</h3><p>Inside <code class="language-text">src/App.js</code>, change the content to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useEffect<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Container <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> GoogleContext <span class="token keyword">from</span> <span class="token string">"./GoogleContext"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>google<span class="token punctuation">,</span> setGoogle<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>google<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> head <span class="token operator">=</span> document<span class="token punctuation">.</span>head<span class="token punctuation">;</span> <span class="token keyword">let</span> script <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'googleChartsScript'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>script<span class="token punctuation">)</span> <span class="token punctuation">{</span> script <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'script'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> script<span class="token punctuation">.</span>src <span class="token operator">=</span> <span class="token string">'https://www.gstatic.com/charts/loader.js'</span><span class="token punctuation">;</span> script<span class="token punctuation">.</span>id <span class="token operator">=</span> <span class="token string">'googleChartsScript'</span><span class="token punctuation">;</span> script<span class="token punctuation">.</span><span class="token function-variable function">onload</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>window<span class="token punctuation">.</span>google <span class="token operator">&&</span> window<span class="token punctuation">.</span>google<span class="token punctuation">.</span>charts<span class="token punctuation">)</span> <span class="token punctuation">{</span> window<span class="token punctuation">.</span>google<span class="token punctuation">.</span>charts<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span><span class="token string">'current'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token string-property property">'packages'</span><span class="token operator">:</span><span class="token punctuation">[</span><span class="token string">'corechart'</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> window<span class="token punctuation">.</span>google<span class="token punctuation">.</span>charts<span class="token punctuation">.</span><span class="token function">setOnLoadCallback</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setGoogle</span><span class="token punctuation">(</span>window<span class="token punctuation">.</span>google<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> head<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>script<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>window<span class="token punctuation">.</span>google<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setGoogle</span><span class="token punctuation">(</span>window<span class="token punctuation">.</span>google<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">let</span> script <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'googleChartsScript'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>script<span class="token punctuation">)</span> <span class="token punctuation">{</span> script<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>google<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>GoogleContext<span class="token punctuation">.</span>Provider value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span>google<span class="token punctuation">,</span> setGoogle<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Container className<span class="token operator">=</span><span class="token string">"mt-3"</span><span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span>With Context<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>GoogleContext<span class="token punctuation">.</span>Provider<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span></code></pre></div><p>Here, we are creating a <code class="language-text">google</code> state. Then, in <code class="language-text">useEffect</code> we are executing the same code that we did previously in <code class="language-text">useGoogleChart</code>. We are loading the script then setting the <code class="language-text">google</code> state when it's loaded.</p><p>Finally, we are surrounding the rendered components with the context provider, passing it the state and its setter as the value. </p><h3 id="create-chart-component">Create Chart Component</h3><p>Next, we'll create the chart component <code class="language-text">src/PizzaChart.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useContext<span class="token punctuation">,</span> useEffect<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Spinner <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> GoogleContext <span class="token keyword">from</span> <span class="token string">"./GoogleContext"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">PizzaChart</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>chart<span class="token punctuation">,</span> setChart<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> google <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useContext</span><span class="token punctuation">(</span>GoogleContext<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>google <span class="token operator">&&</span> <span class="token operator">!</span>chart<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Create the data table.</span> <span class="token keyword">var</span> data <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">window<span class="token punctuation">.</span>google<span class="token punctuation">.</span>visualization<span class="token punctuation">.</span>DataTable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> data<span class="token punctuation">.</span><span class="token function">addColumn</span><span class="token punctuation">(</span><span class="token string">'string'</span><span class="token punctuation">,</span> <span class="token string">'Topping'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> data<span class="token punctuation">.</span><span class="token function">addColumn</span><span class="token punctuation">(</span><span class="token string">'number'</span><span class="token punctuation">,</span> <span class="token string">'Slices'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> data<span class="token punctuation">.</span><span class="token function">addRows</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token punctuation">[</span><span class="token string">'Mushrooms'</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Onions'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Olives'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Zucchini'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Pepperoni'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Set chart options</span> <span class="token keyword">var</span> options <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string-property property">'title'</span><span class="token operator">:</span><span class="token string">'How Much Pizza I Ate Last Night'</span><span class="token punctuation">,</span> <span class="token string-property property">'width'</span><span class="token operator">:</span><span class="token number">400</span><span class="token punctuation">,</span> <span class="token string-property property">'height'</span><span class="token operator">:</span><span class="token number">300</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Instantiate and draw our chart, passing in some options.</span> <span class="token keyword">const</span> newChart <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">window<span class="token punctuation">.</span>google<span class="token punctuation">.</span>visualization<span class="token punctuation">.</span>PieChart</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'pizzaChart'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> newChart<span class="token punctuation">.</span><span class="token function">draw</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setChart</span><span class="token punctuation">(</span>newChart<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>google<span class="token punctuation">,</span> chart<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token operator">!</span>google <span class="token operator">&&</span> <span class="token operator"><</span>Spinner <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator"><</span>div id<span class="token operator">=</span><span class="token string">"pizzaChart"</span> className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token operator">!</span>google <span class="token operator">?</span> <span class="token string">'d-none'</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> PizzaChart<span class="token punctuation">;</span></code></pre></div><p>This chart component is similar to the previous chart component we created in the previous section.</p><p>First, we are creating the state <code class="language-text">chart</code> to only render the chart once. Then, we're retrieving the context using <code class="language-text">useContext</code>. After that, we're drawing the chart inside <code class="language-text">useEffect</code>. Finally, we're rendering a spinner if google is not loaded, and a <code class="language-text">div</code> element that the chart will be drawn in.</p><p>Now, add the component inside the returned JSX in <code class="language-text">src/App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>GoogleContext<span class="token punctuation">.</span>Provider value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span>google<span class="token punctuation">,</span> setGoogle<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Container className<span class="token operator">=</span><span class="token string">"mt-3"</span><span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span>With Context<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>PizzaChart <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>GoogleContext<span class="token punctuation">.</span>Provider<span class="token operator">></span></code></pre></div><p>If you open the website now, you'll see the same Pizza Chart we saw when using hooks.</p><h3 id="multiple-charts-1">Multiple Charts</h3><p>We'll create another chart component <code class="language-text">src/DinosaurChart.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useContext<span class="token punctuation">,</span> useEffect<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Spinner <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> GoogleContext <span class="token keyword">from</span> <span class="token string">"./GoogleContext"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">DinosaurChart</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>chart<span class="token punctuation">,</span> setChart<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> google <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useContext</span><span class="token punctuation">(</span>GoogleContext<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>google <span class="token operator">&&</span> <span class="token operator">!</span>chart<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> data <span class="token operator">=</span> google<span class="token punctuation">.</span>visualization<span class="token punctuation">.</span><span class="token function">arrayToDataTable</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token punctuation">[</span><span class="token string">'Dinosaur'</span><span class="token punctuation">,</span> <span class="token string">'Length'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Acrocanthosaurus (top-spined lizard)'</span><span class="token punctuation">,</span> <span class="token number">12.2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Albertosaurus (Alberta lizard)'</span><span class="token punctuation">,</span> <span class="token number">9.1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Allosaurus (other lizard)'</span><span class="token punctuation">,</span> <span class="token number">12.2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Apatosaurus (deceptive lizard)'</span><span class="token punctuation">,</span> <span class="token number">22.9</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Archaeopteryx (ancient wing)'</span><span class="token punctuation">,</span> <span class="token number">0.9</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Argentinosaurus (Argentina lizard)'</span><span class="token punctuation">,</span> <span class="token number">36.6</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Baryonyx (heavy claws)'</span><span class="token punctuation">,</span> <span class="token number">9.1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Brachiosaurus (arm lizard)'</span><span class="token punctuation">,</span> <span class="token number">30.5</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Ceratosaurus (horned lizard)'</span><span class="token punctuation">,</span> <span class="token number">6.1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Coelophysis (hollow form)'</span><span class="token punctuation">,</span> <span class="token number">2.7</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Compsognathus (elegant jaw)'</span><span class="token punctuation">,</span> <span class="token number">0.9</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Deinonychus (terrible claw)'</span><span class="token punctuation">,</span> <span class="token number">2.7</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Diplodocus (double beam)'</span><span class="token punctuation">,</span> <span class="token number">27.1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Dromicelomimus (emu mimic)'</span><span class="token punctuation">,</span> <span class="token number">3.4</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Gallimimus (fowl mimic)'</span><span class="token punctuation">,</span> <span class="token number">5.5</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Mamenchisaurus (Mamenchi lizard)'</span><span class="token punctuation">,</span> <span class="token number">21.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Megalosaurus (big lizard)'</span><span class="token punctuation">,</span> <span class="token number">7.9</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Microvenator (small hunter)'</span><span class="token punctuation">,</span> <span class="token number">1.2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Ornithomimus (bird mimic)'</span><span class="token punctuation">,</span> <span class="token number">4.6</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Oviraptor (egg robber)'</span><span class="token punctuation">,</span> <span class="token number">1.5</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Plateosaurus (flat lizard)'</span><span class="token punctuation">,</span> <span class="token number">7.9</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Sauronithoides (narrow-clawed lizard)'</span><span class="token punctuation">,</span> <span class="token number">2.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Seismosaurus (tremor lizard)'</span><span class="token punctuation">,</span> <span class="token number">45.7</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Spinosaurus (spiny lizard)'</span><span class="token punctuation">,</span> <span class="token number">12.2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Supersaurus (super lizard)'</span><span class="token punctuation">,</span> <span class="token number">30.5</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Tyrannosaurus (tyrant lizard)'</span><span class="token punctuation">,</span> <span class="token number">15.2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Ultrasaurus (ultra lizard)'</span><span class="token punctuation">,</span> <span class="token number">30.5</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'Velociraptor (swift robber)'</span><span class="token punctuation">,</span> <span class="token number">1.8</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> options <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Lengths of dinosaurs, in meters'</span><span class="token punctuation">,</span> <span class="token literal-property property">legend</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">position</span><span class="token operator">:</span> <span class="token string">'none'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">const</span> newChart <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">google<span class="token punctuation">.</span>visualization<span class="token punctuation">.</span>Histogram</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'dinosaurChart'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> newChart<span class="token punctuation">.</span><span class="token function">draw</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setChart</span><span class="token punctuation">(</span>newChart<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>google<span class="token punctuation">,</span> chart<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token operator">!</span>google <span class="token operator">&&</span> <span class="token operator"><</span>Spinner <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator"><</span>div id<span class="token operator">=</span><span class="token string">"dinosaurChart"</span> className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token operator">!</span>google <span class="token operator">?</span> <span class="token string">'d-none'</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> DinosaurChart<span class="token punctuation">;</span></code></pre></div><p>The code is very similar to <code class="language-text">PizzaChart</code> but the data that is being drawn is different, and a Histogram is being drawn instead of a PieChart.</p><p>Finally, we need to add the <code class="language-text">DinosaurChart</code> component in the returned JSX in <code class="language-text">src/App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>GoogleContext<span class="token punctuation">.</span>Provider value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span>google<span class="token punctuation">,</span> setGoogle<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Container className<span class="token operator">=</span><span class="token string">"mt-3"</span><span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span>With Context<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>PizzaChart <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>DinosaurChart <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>GoogleContext<span class="token punctuation">.</span>Provider<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>If you open the website now, you'll see the 2 charts.</p><h2 id="should-you-use-context-or-hooks">Should You Use Context or Hooks?</h2><p>The approach you use depends on your use case. If you're using one or multiple charts inside the same component, even if as child components, the hook approach can work fine.</p><p>However, if you're using multiple charts spread in different components, the best approach would be to use the context.</p><h2 id="conclusion">Conclusion</h2><p>In this tutorial, we learned how to use Google Charts with React. The implementation can be expanded if necessary based on your use case, as Google Charts have a lot of use cases and packages other than the core packages.</p><p>Make sure to check out <a href="https://developers.google.com/chart">Google Chart's documentation</a> as well for more information.</p>]]></content:encoded></item><item><title><![CDATA[Beginner's Guide to Magento 2: Understanding the Structure]]></title><description><![CDATA[In this article, you'll learn the basics of Magento 2. This article is perfect for beginners who are interested to learn how Magento works.]]></description><link>https://blog.shahednasser.com/beginners-guide-to-magento-2-understanding-the-structure/</link><guid isPermaLink="false">Ghost__Post__61338d42d8016c9d86b23703</guid><category><![CDATA[Magento]]></category><category><![CDATA[Beginners]]></category><category><![CDATA[eCommerce]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 07 Sep 2021 16:09:47 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/b795467fbda234a01c4a207f3b175c62/Beginner-s-Guide-to-Magento-2.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/b795467fbda234a01c4a207f3b175c62/Beginner-s-Guide-to-Magento-2.png" alt="Beginner's Guide to Magento 2: Understanding the Structure"/><p>Magento 2 is a popular e-commerce platform that has a variety of out-of-the-box features and high-security levels. With Magento 2, you're guaranteed to have an e-commerce platform that provides all the necessary functionalities you need and more for your business to flourish.</p><p>In this article, you'll learn the basics of Magento 2. You'll learn about the structure of Magento 2 including, modules, themes, and more, and a brief overview of each. This article is perfect for beginners who are interested to learn how Magento works.</p><h2 id="system-requirements">System Requirements</h2><p>To start working with the latest version of Magento 2, you'll need at least PHP 7.4 (at the time of writing this article). You'll also need <a href="https://www.elastic.co">Elasticsearch</a> installed and running as a background service.</p><p>In addition, you need Composer installed. Composer is necessary to initiate the installation.</p><p>MySQL is also required for the database of Magento 2.</p><p>Once you have these elements installed, you can start installing Magento. There are a few steps before you can get Magento 2 installed and working, so I suggest you follow the <a href="https://devdocs.magento.com/guides/v2.4/install-gde/composer.html">official installation guide</a>.</p><h2 id="directory-structure-overview">Directory Structure Overview</h2><p>We'll go over the directory structure in Magento briefly. After you install Magento, this is how the directory structure should look like:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/09/Screen-Shot-2021-09-04-at-6.26.52-PM.png" class="kg-image" alt="Beginner's Guide to Magento 2: Understanding the Structure" loading="lazy" width="550" height="492"/></figure><p>We'll briefly go over what each directory is:</p><ol><li><strong>app</strong>: This directory is where you'll spend most of your time when programming in Magento 2. It should have three directories: <em>code</em> which is where your custom modules will go into; <em>design</em> which is where your custom themes will go into; and <em>etc</em> which holds the main configuration files for Magento's system and modules or settings.</li><li><strong>bin: </strong>This holds Magento's CLI tool. You'll use this tool to compile, generate static data, run cron jobs, and more.</li><li><strong>dev</strong>: This tool is more related to using tools like <a href="https://gruntjs.com">Grunt</a>. Magento 2 supports Grunt out-of-the-box. Although you don't need to use it, using Grunt with Magento 2 <a href="https://blog.shahednasser.com/how-to-make-your-front-end-development-faster-in-magento-2-using-grunt/">speeds up your frontend development</a>.</li><li><strong>generated</strong>: when creating modules in Magento 2, you'll frequently need to compile the code using the CLI tool. The generated classes and code are all placed inside the <em>generated </em>directory.</li><li><strong>lib</strong>: This includes a set of libraries that are related to Magento's system.</li><li><strong>node_modules: </strong>Only present if you run <code class="language-text">npm install</code>. You can use NPM packages for a variety of reasons, like when you are using Grunt with Magento.</li><li><strong>phpserver</strong>: This directory includes the built-in PHP server.</li><li><strong>pub: </strong>This directory will include public media like images. It will also include the generated static files of both the admin and the store. When you open the website, all the pages and static files are used from this directory.</li><li><strong>setup: </strong>This directory is only necessary when first setting up Magento 2 and installing it.</li><li><strong>var: </strong>This directory includes cache files, logs, and more.</li><li><strong>vendor</strong>: All composer-installed libraries and packages, including Magento's code, will be present in this directory.</li></ol><h2 id="areas">Areas</h2><p>In Magento, there is the admin side which allows you to view all data necessary to the store like customers, sales, and more. It also allows you to change settings in the store. This side is protected by a password and should be only accessed by the managers of the store.</p><p>There's also the storefront, which is the store that the users see and buy items from.</p><p>These two sides are called "areas". The <code class="language-text">adminhtml</code> area refers to the admin side, and the <code class="language-text">frontend</code> area refers to the storefront. When creating modules and themes, you'll see that these area names are used to separate static files, themes, controllers, and more from each other.</p><h2 id="views">Views</h2><p>In both modules and themes, there are view files. These files are what shape each page, and they can be new in your module or theme or override existing files.</p><h3 id="layouts">Layouts</h3><p>Layouts are XML files. One thing you can do with them is creating page layout types. These layout types define different types of structures which can be used when creating pages. For example, by default Magento has the page layout type <code class="language-text">2columns-left</code>, which will show a sidebar at the left of the page. When creating page layouts later, if their type is <code class="language-text">2columns-left</code> they'll have a left sidebar.</p><p>The second type of layout XML files is page layouts which are specific for each page. Their name convention is <code class="language-text">ROUTENAME_CONTROLLER_ACTION.xml</code>, where <code class="language-text">ROUTENAME</code> is defined when you create a new module, <code class="language-text">CONTROLLER</code> is the controller inside that module which is usually a directory, and <code class="language-text">ACTION</code> is one of the action classes inside that controller directory.</p><p>Page layouts consist of containers and blocks. Containers are mainly just HTML element containers, whereas blocks are PHP classes that have templates representing them.</p><h3 id="templates">Templates</h3><p>Templates are what the user will see when we add a block to a page's layout. By default, templates have a block variable inside the template of the class <code class="language-text">Magento\Framework\View\Element\Template</code>, but you can create your own block as well. If you create your own block class, you can create functions or variables inside it that the template can use.</p><h3 id="static-files">Static Files</h3><p>You can add styling through CSS and Less files. If you use Less stylesheets, they'll be compiled when you deploy the static content of your store.</p><p>You can also add Javascript files. Magento 2 uses <a href="https://requirejs.org">RequireJS</a> to load these static files efficiently. So, your Javascript files should support it. </p><p>In Javascript, you can use <a href="https://knockoutjs.com">Knockout</a>. It's a Javascript library that allows you to create dynamic HTML templates.</p><h2 id="modules">Modules</h2><p>In Magento 2, when you want to implement new functionality that's not present in the system, you want to modify or remove existing functionality or want to override how Magento 2 does something, you'll need to create a module for it.</p><h3 id="database-tables">Database Tables</h3><p>You can do many things inside modules. You can create database tables on installation or update or add to existing database tables. You can also insert data into the database.</p><h3 id="models">Models</h3><p>You can create Models that represent database tables. These models can have repositories or factories that will allow you to easily read, insert, update or delete data.</p><h3 id="plugins">Plugins</h3><p>You can create Plugins that allow you to perform actions before, after, or around public functions of any class. You can also entirely override a class and change it to whatever fits your needs.</p><h3 id="settings">Settings</h3><p>Inside every module, there's an <code class="language-text">etc</code> directory. This directory holds mainly XML files that handle the settings and configurations of the module. For example, here is where you would define the route name to access the module.</p><h3 id="controllers">Controllers</h3><p>In modules, you can create Controllers. Controllers handle requests into the module. Usually, Controllers are directories inside the <code class="language-text">Controller</code> directory of the module, and inside each <code class="language-text">Controller</code> directory is a set of PHP classes. Each of these PHP classes is an action, meaning they're pages or endpoints for requests.</p><h3 id="blocks">Blocks</h3><p>You can create Blocks, which are added to and rendered in pages. Blocks allow you to create somewhat reusable components, each focusing on a certain functionality or information to be rendered.</p><h3 id="view-files">View Files</h3><p>Modules can include all the view files mentioned in the previous section for both the store and the admin side. You can create them specifically for your module or modify existing ones in other modules.</p><h3 id="cli-commands">CLI Commands</h3><p>Inside modules, you can define CLI commands that you would use through Magento's CLI command.</p><h3 id="cron-jobs">Cron Jobs</h3><p>Inside modules, you can define cron jobs at certain time spans and classes that perform tasks at the time specified for the cron job.</p><h3 id="observers">Observers</h3><p>Magento 2 allows you to trigger events at any necessary point in your code. It also allows you to listen to triggered events to perform certain actions. That's where observers come in. Observers listen to events triggered either by the same module or other modules.</p><h2 id="themes">Themes</h2><p>Magento 2 uses themes to style your store. With themes, you can override the view files mentioned in previous sections that are created by modules. You can also add new ones to change up the style.</p><p>Themes mainly consist of view files, but they're encapsulated inside directories that represent modules.</p><h2 id="internationalization">Internationalization</h2><p>Magento 2 supports multiple languages in your store. This means that you can localize strings in your templates, blocks, controllers, etc...</p><p>You can also change the static files in a theme, like stylesheets, based on the language of the store.</p><p>You can support different languages in both your theme or module. Translations are done through dictionaries that are CSV files. Magento also provides <a href="https://devdocs.magento.com/guides/v2.4/config-guide/cli/config-cli-subcommands-i18n.html">tools that make creating dictionaries</a> easier.</p><h3 id="ui-components">UI Components</h3><p>UI Components were introduced in later versions of Magento 2. They allow you to create layouts and pages, mainly on the admin side, using UI components that allow for the data to be dynamic and for the loading or saving of the data to be asynchronous.</p><p>By default, Magento provides a large set of <a href="https://devdocs.magento.com/guides/v2.4/ui_comp_guide/bk-ui_comps.html">UI components</a> that you can use on any admin page at any given point. You can also create your own.</p><h2 id="conclusion">Conclusion</h2><p>Through this brief overview, you can see a glimpse of what Magento 2's structure is like. It relies mainly on modules and themes, with necessary components, classes, functionalities, and more inside it.</p><p>By understanding how Magneto's structure is like, you're able to start creating with Magento 2 the functionalities and modifications you need for your store.</p>]]></content:encoded></item><item><title><![CDATA[How to Internationalize a React App]]></title><description><![CDATA[We'll learn how to internationalize a React website including translating content and changing the layout's direction based on the language chosen.]]></description><link>https://blog.shahednasser.com/how-to-internationalize-a-react-app/</link><guid isPermaLink="false">Ghost__Post__612e325ed8016c9d86b23554</guid><category><![CDATA[React]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[CSS]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 02 Sep 2021 07:12:51 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/575f09aa1b1fb35308181d2a3f70cf12/ferenc-almasi-c8h0n7fSTqs-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/575f09aa1b1fb35308181d2a3f70cf12/ferenc-almasi-c8h0n7fSTqs-unsplash-2.jpg" alt="How to Internationalize a React App"/><p>Internationalization, or i18n, is supporting different languages in your website or app. It allows you to gain users from different parts of the world, which leads to growing your website's traffic.</p><p>In this tutorial, we'll learn how to internationalize a React website including translating content and changing the layout's direction based on the language chosen.</p><p>You can find the full code for this tutorial in <a href="https://github.com/shahednasser/react-i18n-tutorial">this GitHub repository</a>.</p><h2 id="setup-website">Setup Website</h2><p>First, we'll set up the React website with <a href="https://create-react-app.dev">Create React App (CRA)</a>. </p><p>Run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-react-app react-i18n-tutorial</code></pre></div><p>Once that is done, change the directory to the project:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> react-i18n-tutorial</code></pre></div><p>You can then start the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><h2 id="install-dependencies">Install Dependencies</h2><p>The easiest way to internationalize a React app is to use the library <a href="https://www.i18next.com">i18next</a>. i18next is an internationalization framework written in Javascript that can be used with many languages and frameworks, but most importantly with <a href="https://react.i18next.com">React</a>.</p><p>Run the following command to install i18next:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> react-i18next i18next --save</code></pre></div><p>In addition, we need to install <a href="https://github.com/i18next/i18next-http-backend">i18next-http-backend</a> which allows us to fetch translations from a directory, and <a href="https://github.com/i18next/i18next-browser-languageDetector">i18next-browser-languagedetector</a> which allows us to detect the user's language:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i i18next-http-backend i18next-browser-languagedetector</code></pre></div><p>Last, we'll install <a href="https://react-bootstrap.github.io">React Bootstrap</a> for simple styling:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> react-bootstrap@next bootstrap@5.1.0</code></pre></div><h2 id="create-the-main-page">Create the Main Page</h2><p>We'll create the main page of the website before working on the internationalization.</p><h3 id="navigation-bar">Navigation Bar</h3><p>We first need the Navigation component. Create <code class="language-text">src/components/Navigation.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> Container<span class="token punctuation">,</span> Nav<span class="token punctuation">,</span> Navbar<span class="token punctuation">,</span> NavDropdown <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Navigation</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Navbar bg<span class="token operator">=</span><span class="token string">"light"</span> expand<span class="token operator">=</span><span class="token string">"lg"</span><span class="token operator">></span> <span class="token operator"><</span>Container<span class="token operator">></span> <span class="token operator"><</span>Navbar<span class="token punctuation">.</span>Brand href<span class="token operator">=</span><span class="token string">"#"</span><span class="token operator">></span>React i18n<span class="token operator"><</span><span class="token operator">/</span>Navbar<span class="token punctuation">.</span>Brand<span class="token operator">></span> <span class="token operator"><</span>Navbar<span class="token punctuation">.</span>Toggle aria<span class="token operator">-</span>controls<span class="token operator">=</span><span class="token string">"basic-navbar-nav"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Navbar<span class="token punctuation">.</span>Collapse id<span class="token operator">=</span><span class="token string">"basic-navbar-nav"</span><span class="token operator">></span> <span class="token operator"><</span>Nav className<span class="token operator">=</span><span class="token string">"me-auto"</span><span class="token operator">></span> <span class="token operator"><</span>NavDropdown title<span class="token operator">=</span><span class="token string">"Language"</span> id<span class="token operator">=</span><span class="token string">"basic-nav-dropdown"</span><span class="token operator">></span> <span class="token operator"><</span>NavDropdown<span class="token punctuation">.</span>Item href<span class="token operator">=</span><span class="token string">"#"</span><span class="token operator">></span>English<span class="token operator"><</span><span class="token operator">/</span>NavDropdown<span class="token punctuation">.</span>Item<span class="token operator">></span> <span class="token operator"><</span>NavDropdown<span class="token punctuation">.</span>Item href<span class="token operator">=</span><span class="token string">"#"</span><span class="token operator">></span>العربية<span class="token operator"><</span><span class="token operator">/</span>NavDropdown<span class="token punctuation">.</span>Item<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>NavDropdown<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Navbar<span class="token punctuation">.</span>Collapse<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Navbar<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Navigation<span class="token punctuation">;</span></code></pre></div><h3 id="heading">Heading</h3><p>Then, we'll create <code class="language-text">src/components/Greeting.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">Greeting</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>h1<span class="token operator">></span>Hello<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Greeting<span class="token punctuation">;</span></code></pre></div><h3 id="text">Text</h3><p>Next, we'll create <code class="language-text">src/components/Text.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">Text</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>p<span class="token operator">></span>Thank you <span class="token keyword">for</span> visiting our website<span class="token punctuation">.</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Text<span class="token punctuation">;</span></code></pre></div><p>Finally, we need to show these components on the website. Change the content of <code class="language-text">src/App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Container <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-bootstrap'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token string">'bootstrap/dist/css/bootstrap.min.css'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Greeting <span class="token keyword">from</span> <span class="token string">'./components/Greeting'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Loading <span class="token keyword">from</span> <span class="token string">'./components/Loading'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Navigation <span class="token keyword">from</span> <span class="token string">'./components/Navigation'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Text <span class="token keyword">from</span> <span class="token string">'./components/Text'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token operator"><</span>Navigation <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Container<span class="token operator">></span> <span class="token operator"><</span>Greeting <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Text <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span> </code></pre></div><p>Run the server now, if it isn't running already. You'll see a simple website with a navigation bar and some text.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/08/Screen-Shot-2021-08-31-at-1.22.22-PM.png" class="kg-image" alt="How to Internationalize a React App" loading="lazy" width="2000" height="295" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/08/Screen-Shot-2021-08-31-at-1.22.22-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/08/Screen-Shot-2021-08-31-at-1.22.22-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/08/Screen-Shot-2021-08-31-at-1.22.22-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/08/Screen-Shot-2021-08-31-at-1.22.22-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><h3 id="configuring-i18next">Configuring i18next</h3><p>The first step of internationalizing React with i18next is to configure and initialize it.</p><p>Create <code class="language-text">src/i18n.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> i18n <span class="token keyword">from</span> <span class="token string">"i18next"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> initReactI18next <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-i18next"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Backend <span class="token keyword">from</span> <span class="token string">'i18next-http-backend'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> I18nextBrowserLanguageDetector <span class="token keyword">from</span> <span class="token string">"i18next-browser-languagedetector"</span><span class="token punctuation">;</span> i18n <span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>Backend<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>I18nextBrowserLanguageDetector<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>initReactI18next<span class="token punctuation">)</span> <span class="token comment">// passes i18n down to react-i18next</span> <span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">fallbackLng</span><span class="token operator">:</span> <span class="token string">'en'</span><span class="token punctuation">,</span> <span class="token literal-property property">debug</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">interpolation</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">escapeValue</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token comment">// react already safes from xss</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> i18n<span class="token punctuation">;</span></code></pre></div><p>We're first importing <code class="language-text">i18n</code> from <code class="language-text">i18next</code>. Then, we're adding <code class="language-text">i18next-http-backend</code> and <code class="language-text">i18next-browser-languagedetector</code> as plugins to <code class="language-text">i18n</code>. We're also adding <code class="language-text">initReactI18next</code> as a plugin to ensure that <code class="language-text">i18next</code> works with React.</p><p>Next, we're initializing <code class="language-text">i18n</code> by passing it an object of options. There are <a href="https://www.i18next.com/overview/configuration-options">many options</a> you can pass to the initializer, but we're passing 3 only. </p><p><code class="language-text">fallbackLng</code> acts as the default language in i18n if no language is detected. Language is detected either from the user's preferred language, or a language they previously chose when using the website.</p><p><code class="language-text">debug</code> enables debug messages in the console. This should not be used in production.</p><p>As for <code class="language-text">escapeValue</code> in <code class="language-text">interpolation</code>, we're setting it to false since React already escapes all strings and is safe from <a href="https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwi3o9eav9vyAhXHX8AKHe31CgAQFnoECAMQAQ&url=https%3A%2F%2Fowasp.org%2Fwww-community%2Fattacks%2Fxss%2F&usg=AOvVaw38Aj4XcszVjxrjA0YToyVk">Cross-Site Scripting (XSS)</a>.</p><h2 id="adding-the-translation-files">Adding the Translation Files</h2><p>By default, <code class="language-text">i18next-http-backend</code> looks for translation files in <code class="language-text">public/locales/{language}/translation.json</code>, where <code class="language-text">{language}</code> would be the code of the language chosen. For example, en for English.</p><p>In this tutorial, we'll have 2 languages on our website, English and Arabic. So, we'll create the directory <code class="language-text">locales</code> and inside we'll create 2 directories <code class="language-text">en</code> and <code class="language-text">ar</code>.</p><p>Then, create the file <code class="language-text">translation.json</code> inside <code class="language-text">en</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"greeting"</span><span class="token operator">:</span> <span class="token string">"Hello"</span><span class="token punctuation">,</span> <span class="token property">"text"</span><span class="token operator">:</span> <span class="token string">"Thank you for visiting our website."</span><span class="token punctuation">,</span> <span class="token property">"language"</span><span class="token operator">:</span> <span class="token string">"Language"</span> <span class="token punctuation">}</span></code></pre></div><p>This will create 3 translation keys. When these keys are used, the string value that the key corresponds to will be outputted based on the chosen language. So, each language file should have the same keys but with the values translated to that language.</p><p>Next, we'll create the file <code class="language-text">translation.json</code> inside <code class="language-text">ar</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"greeting"</span><span class="token operator">:</span> <span class="token string">"مرحبا"</span><span class="token punctuation">,</span> <span class="token property">"text"</span><span class="token operator">:</span> <span class="token string">"شكرا لزيارة موقعنا"</span><span class="token punctuation">,</span> <span class="token property">"language"</span><span class="token operator">:</span> <span class="token string">" اللغة"</span> <span class="token punctuation">}</span></code></pre></div><h2 id="using-the-i18n-instance">Using the i18n Instance</h2><p>The next step is importing the file with the settings we just created in <code class="language-text">App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> i18n <span class="token keyword">from</span> <span class="token string">'./i18n'</span><span class="token punctuation">;</span></code></pre></div><p>Next, to make sure that the components are rendered once i18next and the translation files have been loaded, we need to surround our components with <a href="https://reactjs.org/docs/concurrent-mode-suspense.html#what-is-suspense-exactly">Suspense from React</a>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Suspense fallback<span class="token operator">=</span><span class="token punctuation">{</span><span class="token operator"><</span>Loading <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Navigation <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Container<span class="token operator">></span> <span class="token operator"><</span>Greeting <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Text <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Suspense<span class="token operator">></span></code></pre></div><p>As you can see, we're passing a new component <code class="language-text">Loading</code> as a fallback while i18next loads with the translation files. So, we need to create <code class="language-text">src/components/Loading.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> Spinner <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Loading</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Spinner animation<span class="token operator">=</span><span class="token string">"border"</span> role<span class="token operator">=</span><span class="token string">"status"</span><span class="token operator">></span> <span class="token operator"><</span>span className<span class="token operator">=</span><span class="token string">"visually-hidden"</span><span class="token operator">></span>Loading<span class="token operator">...</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Spinner<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Loading<span class="token punctuation">;</span></code></pre></div><p>Now, we're able to translate strings in the <code class="language-text">App</code> components and its sub-components.</p><h2 id="translating-strings-with-usetranslation">Translating Strings with useTranslation</h2><p>There are different ways you can translate strings in i18next, and one of them is using <code class="language-text">useTranslation</code> hook. With this hook, you'll get the translation function which you can use to translate strings.</p><p>We'll start by translating the <code class="language-text">Greeting</code> component. Add the following at the beginning of the component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">Greeting</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> t <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useTranslation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">...</span> <span class="token punctuation">}</span></code></pre></div><p>Then, inside the returned JSX, instead of just placing the text "Hello", we'll replace it with the translation function <code class="language-text">t</code> that we received from <code class="language-text">useTranslation</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>h1<span class="token operator">></span><span class="token punctuation">{</span><span class="token function">t</span><span class="token punctuation">(</span><span class="token string">'greeting'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Note how we're passing the translation function a key that we added in the <code class="language-text">translation.json</code> files for each of the languages. i18next will fetch the value based on the current language.</p><p>We'll do the same thing for the <code class="language-text">Text</code> component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useTranslation <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-i18next"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Text</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> t <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useTranslation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>p<span class="token operator">></span><span class="token punctuation">{</span><span class="token function">t</span><span class="token punctuation">(</span><span class="token string">'text'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Text<span class="token punctuation">;</span></code></pre></div><p>Finally, we'll translate the text "Language" inside the <code class="language-text">Navigation</code> component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>NavDropdown title<span class="token operator">=</span><span class="token punctuation">{</span><span class="token function">t</span><span class="token punctuation">(</span><span class="token string">'language'</span><span class="token punctuation">)</span><span class="token punctuation">}</span> id<span class="token operator">=</span><span class="token string">"basic-nav-dropdown"</span><span class="token operator">></span></code></pre></div><p>If you open the website now, you'll see that nothing has changed. The text is still in English. </p><p>Although technically nothing has changed, considering we are using the translation function passing it the keys instead of the actual strings and it's outputting the correct strings, that means that i18next is loading the translations and is displaying the correct language.</p><p>If we try to change the language using the dropdown in the navigation bar, nothing will happen. We need to change the language based on the language clicked.</p><h2 id="changing-the-language-of-the-website">Changing the Language of the Website</h2><p>The user should be able to change the language of a website. To manage and change the current language of the website, we need to create a context that's accessible by all the parts of the app. </p><p>Creating a context eliminates the need to pass a state through different components and levels.</p><p>Create the file <code class="language-text">src/LocaleContext.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">const</span> defaultValue <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">locale</span><span class="token operator">:</span> <span class="token string">'en'</span><span class="token punctuation">,</span> <span class="token function-variable function">setLocale</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> React<span class="token punctuation">.</span><span class="token function">createContext</span><span class="token punctuation">(</span>defaultValue<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Then, create the state <code class="language-text">locale</code> inside <code class="language-text">src/App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>locale<span class="token punctuation">,</span> setLocale<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span>i18n<span class="token punctuation">.</span>language<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>As you can see, we're passing <code class="language-text">i18n.language</code> as an initial value. The <code class="language-text">language</code> property represents the current language chosen.</p><p>However, as it takes time for i18n to load with the translations, the initial value will be <code class="language-text">undefined</code>. So, we need to listen to the <code class="language-text">languageChanged</code> event that <code class="language-text">i18n</code> triggers when the language is first loaded and when it changes:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">i18n<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'languageChanged'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">lng</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setLocale</span><span class="token punctuation">(</span>i18n<span class="token punctuation">.</span>language<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Finally, we need to surround the returned JSX with the provider of the context:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>LocaleContext<span class="token punctuation">.</span>Provider value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span>locale<span class="token punctuation">,</span> setLocale<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Suspense fallback<span class="token operator">=</span><span class="token punctuation">{</span><span class="token operator"><</span>Loading <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Navigation <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Container<span class="token operator">></span> <span class="token operator"><</span>Greeting <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Text <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Suspense<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>LocaleContext<span class="token punctuation">.</span>Provider<span class="token operator">></span></code></pre></div><p>Now, we can access the locale and its setter from any of the subcomponents.</p><p>To change the language, we need to have a listener function for the click events on the dropdown links.</p><p>In <code class="language-text">src/components/Navigation.js</code> get the locale state from the context at the beginning of the function:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> locale <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useContext</span><span class="token punctuation">(</span>LocaleContext<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Then, add a listener component that will change the language in <code class="language-text">i18n</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"> <span class="token keyword">function</span> <span class="token function">changeLocale</span> <span class="token punctuation">(</span><span class="token parameter">l</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>locale <span class="token operator">!==</span> l<span class="token punctuation">)</span> <span class="token punctuation">{</span> i18n<span class="token punctuation">.</span><span class="token function">changeLanguage</span><span class="token punctuation">(</span>l<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>Finally, we'll bind the listener to the click event for both of the dropdown links:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>NavDropdown<span class="token punctuation">.</span>Item href<span class="token operator">=</span><span class="token string">"#"</span> onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">changeLocale</span><span class="token punctuation">(</span><span class="token string">'en'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>English<span class="token operator"><</span><span class="token operator">/</span>NavDropdown<span class="token punctuation">.</span>Item<span class="token operator">></span> <span class="token operator"><</span>NavDropdown<span class="token punctuation">.</span>Item href<span class="token operator">=</span><span class="token string">"#"</span> onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">changeLocale</span><span class="token punctuation">(</span><span class="token string">'ar'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>العربية<span class="token operator"><</span><span class="token operator">/</span>NavDropdown<span class="token punctuation">.</span>Item<span class="token operator">></span></code></pre></div><p>If you go on the website and try to change the language, you'll see that the language changes successfully based on what you choose. Also, if you try changing the language then refreshing the page, you'll see that the chosen language will persist.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/08/Screen-Shot-2021-08-31-at-1.22.32-PM.png" class="kg-image" alt="How to Internationalize a React App" loading="lazy" width="2000" height="269" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/08/Screen-Shot-2021-08-31-at-1.22.32-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/08/Screen-Shot-2021-08-31-at-1.22.32-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/08/Screen-Shot-2021-08-31-at-1.22.32-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/08/Screen-Shot-2021-08-31-at-1.22.32-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><h2 id="changing-the-location-of-the-translation-files">Changing the Location of the Translation Files</h2><p>As mentioned earlier, the default location of the translation files is in <code class="language-text">public/locales/{language}/translation.json</code>. However, this can be changed.</p><p>To change the default location, change this line in <code class="language-text">src/i18n.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>Backend<span class="token punctuation">)</span></code></pre></div><p>To the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Backend</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">loadPath</span><span class="token operator">:</span> <span class="token string">'/translations/{{lng}}/{{ns}}.json'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre></div><p>Where the <code class="language-text">loadPath</code> is relative to <code class="language-text">public</code>. So, if you use the above path it means the translation files should be in a directory called <code class="language-text">translations</code>.</p><p><code class="language-text">{{lng}}</code> refers to the language, for example, <code class="language-text">en</code>. <code class="language-text">{{ns}}</code> refers to the namespace, which by default is <code class="language-text">translation</code>. </p><p>You can also provide a function as a value of <code class="language-text">loadPath</code> which takes the language as the first parameter and the namespace as the second parameter.</p><h2 id="changing-document-direction">Changing Document Direction</h2><p>The next essential part of internationalization and localization is supporting different directions based on the languages you support. </p><p>If you have Right-to-Left (RTL) languages, you should be able to change the direction of the document when the RTL language is chosen.</p><p>If you use our website as an example, you'll see that although the text is translated when the Arabic language is chosen, the direction is still Left-to-Right (LTR).</p><p>This is not related to i18next as this is done through CSS. In this tutorial, we'll see how we can use <a href="https://getbootstrap.com/docs/5.1/getting-started/rtl/">RTL</a> in Bootstrap 5 to support RTL languages.</p><p>The first thing we need to do is adding the <code class="language-text">dir</code> and <code class="language-text">lang</code> attributes to the <code class="language-text"><html></code> tag of the document. To do that, we need to install <a href="https://www.npmjs.com/package/react-helmet">React Helmet</a>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i react-helmet</code></pre></div><p>Then, inside <code class="language-text">Suspense</code> in the returned JSX of the <code class="language-text">App</code> component add the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Helmet htmlAttributes<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">lang</span><span class="token operator">:</span> locale<span class="token punctuation">,</span> <span class="token literal-property property">dir</span><span class="token operator">:</span> locale <span class="token operator">===</span> <span class="token string">'en'</span> <span class="token operator">?</span> <span class="token string">'ltr'</span> <span class="token operator">:</span> <span class="token string">'rtl'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>This will change the <code class="language-text">lang</code> and <code class="language-text">dir</code> attributes of <code class="language-text"><html></code> based on the value of the locale.</p><p>The next thing we need to do is surround the Bootstrap components with <code class="language-text">ThemeProvider</code> which is a component from <code class="language-text">react-bootstrap</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>ThemeProvider dir<span class="token operator">=</span><span class="token punctuation">{</span>locale <span class="token operator">===</span> <span class="token string">'en'</span> <span class="token operator">?</span> <span class="token string">'ltr'</span> <span class="token operator">:</span> <span class="token string">'rtl'</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Navigation <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Container<span class="token operator">></span> <span class="token operator"><</span>Greeting <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Text <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>ThemeProvider<span class="token operator">></span></code></pre></div><p>As you can see we're passing it the <code class="language-text">dir</code> prop with the direction based on the locale. This is necessary as <code class="language-text">react-bootstrap</code> will load the necessary stylesheet based on whether the current direction is <code class="language-text">rtl</code> or <code class="language-text">ltr</code>.</p><p>Finally, we need to change the class name of <code class="language-text">Nav</code> in the <code class="language-text">Navigation</code> component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Nav className<span class="token operator">=</span><span class="token punctuation">{</span>locale <span class="token operator">===</span> <span class="token string">'en'</span> <span class="token operator">?</span> <span class="token string">'ms-auto'</span> <span class="token operator">:</span> <span class="token string">'me-auto'</span><span class="token punctuation">}</span><span class="token operator">></span></code></pre></div><p>This is only necessary since there seems to be a problem in the support for <code class="language-text">ms-auto</code> when switching to RTL.</p><p>If you try opening the website now and changing the language to Arabic, you'll see that the direction of the document is changed as well.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/08/Screen-Shot-2021-08-31-at-6.50.37-PM.png" class="kg-image" alt="How to Internationalize a React App" loading="lazy" width="2000" height="277" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/08/Screen-Shot-2021-08-31-at-6.50.37-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/08/Screen-Shot-2021-08-31-at-6.50.37-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/08/Screen-Shot-2021-08-31-at-6.50.37-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/08/Screen-Shot-2021-08-31-at-6.50.37-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><h2 id="conclusion">Conclusion</h2><p>i18next facilitates internationalizing your React app, as well as other frameworks and languages. By internationalizing your app or website, you are inviting more users from around the world to use it.</p><p>The main parts of internationalization are translating the content, supporting the direction of the chosen language in your website's stylesheets, and remembering the user's choice. Using i18next you're able to easily translate the content as well as remembering the user's choice.</p>]]></content:encoded></item><item><title><![CDATA[How to Style an Audio Element]]></title><description><![CDATA[In this tutorial, we'll check how we can style audio elements with their pseudo-element selectors, and how we can style them completely from scratch.]]></description><link>https://blog.shahednasser.com/how-to-style-an-audio-element/</link><guid isPermaLink="false">Ghost__Post__6128fded2f96720ecb595dca</guid><category><![CDATA[CSS]]></category><category><![CDATA[Beginners]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 30 Aug 2021 11:06:50 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/6442d5682c1a7a2e766617a762f38531/jexo-tj7Bj_743JA-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/6442d5682c1a7a2e766617a762f38531/jexo-tj7Bj_743JA-unsplash-2.jpg" alt="How to Style an Audio Element"/><p>Audio elements can be tricky to style. There is no straightforward way to style them, as applying CSS styles on <code class="language-text">audio</code> directly does not work.</p><p>In this tutorial, we'll learn 2 ways of styling audios. We'll check how we can style audio elements with their pseudo-element selectors, then we'll see how we can style them completely from scratch.</p><p>This tutorial uses CodePens to show examples on the go. You can check out the <a href="https://codepen.io/collection/pgvvxz">full collection</a>, as well.</p><p>The audio used in this tutorial is free audio from <a href="https://www.zapsplat.com">ZapSplat</a>.</p><h2 id="using-pseudo-element-selectors">Using Pseudo-Element Selectors</h2><p>Audio elements, by default, are not visible. You need to add the <code class="language-text">controls</code> attribute for their controls to be visible.</p><p>This is how a basic audio player looks like:</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_JjJdeqM" src="https://codepen.io/shahednasser/embed/preview/JjJdeqM?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=JjJdeqM" title="Basic Audio Player" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><p>Audio elements have the following pseudo-element selectors in CSS:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-panel <span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-mute-button <span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-play-button <span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-timeline-container <span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-current-time-display <span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-time-remaining-display <span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-timeline <span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-volume-slider-container <span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-volume-slider <span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-seek-back-button <span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-seek-forward-button <span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-fullscreen-button <span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-rewind-button <span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-return-to-realtime-button <span class="token property">audio</span><span class="token punctuation">:</span><span class="token punctuation">:</span>-webkit-media-controls-toggle-closed-captions-button</code></pre></div><p>Using these selectors, you can give basic styling to audio elements. However, these only work on select browsers like Chrome. </p><p>We'll see a few examples of how we can use some of these selectors to style the audio element.</p><p>All the examples below will only work on Chrome. So, if you want to see how the audio element's style changes, please use Chrome.</p><h3 id="styling-the-control-panel">Styling the Control Panel</h3><p>To style the control panel, which is the container of all the audio's controls, you can use the selector <code class="language-text">audio::-webkit-media-controls-panel</code>. In the example below, we use the selector to change the background color.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_gORpZby" src="https://codepen.io/shahednasser/embed/preview/gORpZby?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=gORpZby" title="Styled Controls Panel" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h3 id="styling-the-mute-button">Styling the Mute Button</h3><p>To style the mute button, you can use the selector <code class="language-text">audio::-webkit-media-controls-mute-button</code>. In the example below, we change the background color of the mute button as well as add a border-radius.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_YzQXdwR" src="https://codepen.io/shahednasser/embed/preview/YzQXdwR?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=YzQXdwR" title="Styling Mute Button" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h3 id="styling-the-play-button">Styling the Play Button</h3><p>To style the play button, you can use the selector <code class="language-text">audio::-webkit-media-controls-play-button</code>. In the example below, we change the background color of the play button as well as add a border-radius.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_eYRNbzR" src="https://codepen.io/shahednasser/embed/preview/eYRNbzR?default-tabs=css%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=eYRNbzR" title="Styling Play Button" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h3 id="style-the-current-time">Style the Current Time</h3><p>To style the current time you can use the selector <code class="language-text">audio::-webkit-media-controls-current-time-display</code>. In the example below, we change the color of the text.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_YzQXdQg" src="https://codepen.io/shahednasser/embed/preview/YzQXdQg?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=YzQXdQg" title="Styling Current Time" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h3 id="style-the-remaining-time">Style the Remaining Time</h3><p>To style the remaining time you can use the selector <code class="language-text">audio::-webkit-media-controls-time-remaining-display</code>. In the example below, we change the color of the text.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_NWgqevN" src="https://codepen.io/shahednasser/embed/preview/NWgqevN?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=NWgqevN" title="Styling Remaining Time" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h3 id="style-the-timeline">Style the Timeline</h3><p>To style the timeline you can use the selector <code class="language-text">audio::-webkit-media-controls-timeline</code>. In the example below, we add a background color and a border radius.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_NWgqeaN" src="https://codepen.io/shahednasser/embed/preview/NWgqeaN?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=NWgqeaN" title="Styling Timeline" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h3 id="styling-the-volume-slider">Styling the Volume Slider</h3><p>To style the volume slider, which on Chrome appears after hovering the mute button, you can use the selector <code class="language-text">audio::-webkit-media-controls-volume-slider</code>. In the example below, we add a background color, a border radius, and some padding.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_ZEyGVaX" src="https://codepen.io/shahednasser/embed/preview/ZEyGVaX?default-tabs=css%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=ZEyGVaX" title="Styling Volume Slider" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><h2 id="styling-a-custom-audio-player">Styling a Custom Audio Player</h2><p>In this section, we'll create our own custom audio player. We'll a nice looking player that uses different elements to achieve a good style. Then with the help of Javascript bind the audio element's functionalities to these elements.</p><p>All the icons used in this section are from <a href="https://heroicons.com/">Heroicons</a>.</p><p>You can see the full demo on CodePen at the end of the section.</p><h3 id="create-the-track-image">Create the Track Image</h3><p>Usually, audio players have an image of the track playing. It gives a nice style to the audio player. We'll just an icon from Heroicons to simulate that. </p><p>We'll start by adding in the HTML the container <code class="language-text">.audio-player</code>. Inside that container, we'll add the track "image" element.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>audio-player<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>icon-container<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>svg</span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>audio-icon<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 20 20<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>currentColor<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>path</span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>M18 3a1 1 0 00-1.196-.98l-10 2A1 1 0 006 5v9.114A4.369 4.369 0 005 14c-1.657 0-3 .895-3 2s1.343 2 3 2 3-.895 3-2V7.82l8-1.6v5.894A4.37 4.37 0 0015 12c-1.657 0-3 .895-3 2s1.343 2 3 2 3-.895 3-2V3z<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>svg</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>audio</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://www.zapsplat.com/wp-content/uploads/2015/sound-effects-61905/zapsplat_multimedia_alert_chime_short_musical_notification_cute_child_like_001_64918.mp3?_=1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>audio</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre></div><p>Then, we'll add some CSS to style these elements.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.audio-player</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 15rem<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 15rem<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.icon-container</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> #DE5E97<span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span> <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span> <span class="token property">justify-content</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.audio-icon</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 90%<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 90%<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will create the following audio track image.</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/08/Screen-Shot-2021-08-27-at-5.57.19-PM.png" class="kg-image" alt="How to Style an Audio Element" loading="lazy" width="536" height="518"/></figure><p>This has nothing to do with the actual functionality of the audio. It's just to make the visual nice.</p><h3 id="add-the-play-button">Add the Play Button</h3><p>Next, we'll add the play button. There are 3 phases of adding the play button: adding the HTML elements, adding the CSS styling, then implementing the Javascript functionality.</p><p><strong>Add the HTML elements</strong></p><p>Add the following inside the <code class="language-text">.audio-player</code> element:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>controls<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>player-button<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>svg</span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 20 20<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#3D3132<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>path</span> <span class="token attr-name">fill-rule</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>evenodd<span class="token punctuation">"</span></span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z<span class="token punctuation">"</span></span> <span class="token attr-name">clip-rule</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>evenodd<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>svg</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre></div><p>This will add a container <code class="language-text">.controls</code> element, then inside it, we're adding a button that has a play icon inside.</p><p><strong>Add the CSS styles</strong></p><p>Next, we'll add the CSS styles for the <code class="language-text">.controls</code> element and the button. </p><p>First, add the following <a href="https://blog.shahednasser.com/css-variables-and-how-to-use-them">CSS Variable</a> inside <code class="language-text">.audio-player</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.audio-player</span> <span class="token punctuation">{</span> <span class="token property">--player-button-width</span><span class="token punctuation">:</span> 3em<span class="token punctuation">;</span> ... <span class="token punctuation">}</span></code></pre></div><p>Then, add the following CSS to style the <code class="language-text">.controls</code> and <code class="language-text">.player-button</code> elements:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.controls</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span> <span class="token property">flex-direction</span><span class="token punctuation">:</span> row<span class="token punctuation">;</span> <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">margin-top</span><span class="token punctuation">:</span> 10px<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.player-button</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> transparent<span class="token punctuation">;</span> <span class="token property">border</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--player-button-width<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--player-button-width<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span> <span class="token property">padding</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will style the <code class="language-text">.controls</code> element to be a flexbox element. This will allow us to align the controls (which we will add more later) inside nicely.</p><p>The player button just has a transparent background and no border, as we just want to show the icon inside.</p><p>This will produce the following UI:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/08/Screen-Shot-2021-08-27-at-5.57.42-PM.png" class="kg-image" alt="How to Style an Audio Element" loading="lazy" width="546" height="612"/></figure><p>However, clicking the button now does nothing. We need to use Javascript to bind the functionalities to the audio.</p><p><strong>Bind the Functionality with Javascript</strong></p><p>In Javascript, we'll first define some variables:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> playerButton <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.player-button'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> audio <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'audio'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> playIcon <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132"> <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" /> </svg> </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> pauseIcon <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132"> <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" /> </svg> </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></code></pre></div><p>We've defined <code class="language-text">playerButton</code> which is the player button element, <code class="language-text">audio</code> which is the audio this player is for, <code class="language-text">playIcon</code> and <code class="language-text">pauseIcon</code> which we will use to toggle the icon of the button.</p><p>Then, we'll create the function that should be triggered when the button is clicked:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">toggleAudio</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>audio<span class="token punctuation">.</span>paused<span class="token punctuation">)</span> <span class="token punctuation">{</span> audio<span class="token punctuation">.</span><span class="token function">play</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> playerButton<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> pauseIcon<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> audio<span class="token punctuation">.</span><span class="token function">pause</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> playerButton<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> playIcon<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>This function checks whether the audio is paused or playing, then it either plays or pauses it. It also changes the icon of <code class="language-text">playerButton</code>.</p><p>Next, add the function as an event listener to the click event of <code class="language-text">playerButton</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">playerButton<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> toggleAudio<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>We also need to update the icon of <code class="language-text">playerButton</code> when the audio ends. To do that, we can use the audio element's event <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/ended_event">ended</a> and in the listener change the icon back to the play icon:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">audioEnded</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> playerButton<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> playIcon<span class="token punctuation">;</span> <span class="token punctuation">}</span> audio<span class="token punctuation">.</span>onended <span class="token operator">=</span> audioEnded<span class="token punctuation">;</span></code></pre></div><p>You can try to play the audio by clicking on the play button, and the audio will work!</p><h3 id="add-the-timeline-track">Add the Timeline Track</h3><p>Next, we need to add the timeline track, which will allow us to see the progress of the audio, as well as seek through the audio.</p><p>To implement the audio timeline track, the easiest approach is to use a <a href="https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwiw5PmPxdHyAhUC4BoKHbV2DzgQFnoECAkQAQ&url=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FWeb%2FHTML%2FElement%2Finput%2Frange&usg=AOvVaw3-3hJWlge4BGAI_YzitUwT">range input</a>. Using the range input, we'll first style it with CSS, then bind the functionalities in Javascript.</p><p><strong>Add the HTML elements</strong></p><p>Inside <code class="language-text">.controls</code> add the following input range:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>range<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>timeline<span class="token punctuation">"</span></span> <span class="token attr-name">max</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>100<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code></pre></div><p><strong>Add the CSS styles</strong></p><p>To style a range input, there are two elements to take into account: the thumb, which allows us to change the value of the input, and the track that the thumb resides on.</p><p>To style the thumb, the following cross-browser selectors are used:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token property">-webkit-slider-thumb</span> <span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token property">-moz-range-thumb</span> <span class="token punctuation">:</span><span class="token punctuation">:</span>-ms-thumb</code></pre></div><p>and the following cross-browser selectors are used to style the track:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token property">-webkit-slider-runnable-track</span> <span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token property">-moz-range-track</span> <span class="token punctuation">:</span><span class="token punctuation">:</span>-ms-track</code></pre></div><p>For the simplicity of this tutorial and to avoid repetition, we'll just show the code for <code class="language-text">-webkit</code> selectors. You can find the full, cross-browser code in the demo CodePen.</p><p>We'll first style the input range itself:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.timeline</span> <span class="token punctuation">{</span> <span class="token property">-webkit-appearance</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>100% - <span class="token function">var</span><span class="token punctuation">(</span>--player-button-width<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> .5em<span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> #e5e5e5<span class="token punctuation">;</span> <span class="token property">border-radius</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span> <span class="token property">background-size</span><span class="token punctuation">:</span> 0% 100%<span class="token punctuation">;</span> <span class="token property">background-image</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span>#DE5E97<span class="token punctuation">,</span> #DE5E97<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">background-repeat</span><span class="token punctuation">:</span> no-repeat<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Using <code class="language-text">-webkit-appearance: none;</code> is necessary to be able to apply the styling.</p><p>Using <code class="language-text">linear-gradient(#DE5E97, #DE5E97);</code> for <code class="language-text">background-image</code> allows us to easily add the progress track of a different color based on the current progress of the audio.</p><p>To change the size of the background image, which means the position of the current progress in the audio, we use <code class="language-text">background-size: 0% 100%;</code>. The first value is the width. It will be the value we'll update through Javascript to show the progress of the audio.</p><p>Next, we'll add the styling of the thumb:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.timeline::-webkit-slider-thumb</span> <span class="token punctuation">{</span> <span class="token property">-webkit-appearance</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 1em<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 1em<span class="token punctuation">;</span> <span class="token property">border-radius</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span> <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span> <span class="token property">opacity</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">transition</span><span class="token punctuation">:</span> all .1s<span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> #a94672<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.timeline::-webkit-slider-thumb:hover</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> #943f65<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.timeline:hover::-webkit-slider-thumb</span> <span class="token punctuation">{</span> <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>We're just adding some styling to the thumb, and we're hiding it and showing it on hover.</p><p>Then, we'll basically hide the track as we'll just use the styling in <code class="language-text">.timeline</code> to show the track and the progress of the audio:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.timeline::-webkit-slider-runnable-track</span> <span class="token punctuation">{</span> <span class="token property">-webkit-appearance</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">box-shadow</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">border</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token property">background</span><span class="token punctuation">:</span> transparent<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>The track will look like this:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/08/Screen-Shot-2021-08-27-at-5.58.03-PM.png" class="kg-image" alt="How to Style an Audio Element" loading="lazy" width="526" height="612"/></figure><h3 id="bind-the-javascript-functionality">Bind the Javascript Functionality</h3><p>We just need to add the Javascript functionality now. The track should show the progress of the audio, and it should allow changing the progress of the audio by moving the thumb.</p><p>First, we'll define the <code class="language-text">timeline</code> variable for the element:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> timeline <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.timeline'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Then, we'll add the function that will listen to the <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/timeupdate_event">timeupdate</a> event. The <code class="language-text">timeupdate</code> event is triggered whenever the audio's time changes. So, it's triggered continuously as the audio is playing, and it's triggered when the audio <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/currentTime">currentTime</a> attribute is updated.</p><p>The function will calculate the progress of the audio in percentage using audio's currentTime attribute and audio's <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/duration">duration</a> attribute. Then, will set the <code class="language-text">backgroundSize</code> CSS property of the <code class="language-text">timeline</code> element based on the calculation:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">changeTimelinePosition</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> percentagePosition <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">100</span><span class="token operator">*</span>audio<span class="token punctuation">.</span>currentTime<span class="token punctuation">)</span> <span class="token operator">/</span> audio<span class="token punctuation">.</span>duration<span class="token punctuation">;</span> timeline<span class="token punctuation">.</span>style<span class="token punctuation">.</span>backgroundSize <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>percentagePosition<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">% 100%</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> timeline<span class="token punctuation">.</span>value <span class="token operator">=</span> percentagePosition<span class="token punctuation">;</span> <span class="token punctuation">}</span> audio<span class="token punctuation">.</span>ontimeupdate <span class="token operator">=</span> changeTimelinePosition<span class="token punctuation">;</span></code></pre></div><p>Next, we need to add the function that will handle the change event of the input range button, then change the progress of the audio as well as the <code class="language-text">backgroundSize</code> CSS property:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">changeSeek</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> time <span class="token operator">=</span> <span class="token punctuation">(</span>timeline<span class="token punctuation">.</span>value <span class="token operator">*</span> audio<span class="token punctuation">.</span>duration<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">100</span><span class="token punctuation">;</span> audio<span class="token punctuation">.</span>currentTime <span class="token operator">=</span> time<span class="token punctuation">;</span> <span class="token punctuation">}</span> timeline<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'change'</span><span class="token punctuation">,</span> changeSeek<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>You can now play the audio and see how the track shows the progress of the audio. You can also try changing the progress by moving the thumb.</p><h3 id="add-the-sound-button">Add the Sound Button</h3><p>The last thing we'll do is add a sound button. This button will just toggle the sound of the audio, muting and unmuting it.</p><p><strong>Add the HTML elements</strong></p><p>Add the following HTML elements inside <code class="language-text">.controls</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sound-button<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>svg</span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 20 20<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#3D3132<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>path</span> <span class="token attr-name">fill-rule</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>evenodd<span class="token punctuation">"</span></span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM14.657 2.929a1 1 0 011.414 0A9.972 9.972 0 0119 10a9.972 9.972 0 01-2.929 7.071 1 1 0 01-1.414-1.414A7.971 7.971 0 0017 10c0-2.21-.894-4.208-2.343-5.657a1 1 0 010-1.414zm-2.829 2.828a1 1 0 011.415 0A5.983 5.983 0 0115 10a5.984 5.984 0 01-1.757 4.243 1 1 0 01-1.415-1.415A3.984 3.984 0 0013 10a3.983 3.983 0 00-1.172-2.828 1 1 0 010-1.415z<span class="token punctuation">"</span></span> <span class="token attr-name">clip-rule</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>evenodd<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>svg</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span></code></pre></div><p>This is just a button with an icon.</p><p><strong>Add the CSS Styles</strong></p><p>Next, we need to add the CSS styles.</p><p>First, add 2 new variables inside <code class="language-text">.audio-player</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.audio-player</span> <span class="token punctuation">{</span> <span class="token property">--player-button-width</span><span class="token punctuation">:</span> 3em<span class="token punctuation">;</span> <span class="token property">--sound-button-width</span><span class="token punctuation">:</span> 2em<span class="token punctuation">;</span> <span class="token property">--space</span><span class="token punctuation">:</span> .5em<span class="token punctuation">;</span> ... <span class="token punctuation">}</span></code></pre></div><p>The <code class="language-text">--sound-button-width</code> will be used for the width of the sound button, and <code class="language-text">--space</code> will be used to add space between the track and the button.</p><p>Next, change the <code class="language-text">width</code> of the <code class="language-text">.timeline</code> element and add a <code class="language-text">margin-right</code> property as well:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.timeline</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>100% - <span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--player-button-width<span class="token punctuation">)</span> + <span class="token function">var</span><span class="token punctuation">(</span>--sound-button-width<span class="token punctuation">)</span> + <span class="token function">var</span><span class="token punctuation">(</span>--space<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">margin-right</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--space<span class="token punctuation">)</span><span class="token punctuation">;</span> ... <span class="token punctuation">}</span></code></pre></div><p>Finally, add the CSS styling for the sound button:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.sound-button</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> transparent<span class="token punctuation">;</span> <span class="token property">border</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--sound-button-width<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--sound-button-width<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span> <span class="token property">padding</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>We'll now have a sound button next to the track:</p><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/08/Screen-Shot-2021-08-27-at-5.58.19-PM.png" class="kg-image" alt="How to Style an Audio Element" loading="lazy" width="558" height="596"/></figure><p><strong>Bind the Javascript Functionality</strong></p><p>Lastly, we just need to bind the functionality of the sound button to the audio element. Clicking the sound button should mute or unmute the sound of the audio.</p><p>First, add the following new variable definitions:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> soundButton <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.sound-button'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> soundIcon <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132"> <path fill-rule="evenodd" d="M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM14.657 2.929a1 1 0 011.414 0A9.972 9.972 0 0119 10a9.972 9.972 0 01-2.929 7.071 1 1 0 01-1.414-1.414A7.971 7.971 0 0017 10c0-2.21-.894-4.208-2.343-5.657a1 1 0 010-1.414zm-2.829 2.828a1 1 0 011.415 0A5.983 5.983 0 0115 10a5.984 5.984 0 01-1.757 4.243 1 1 0 01-1.415-1.415A3.984 3.984 0 0013 10a3.983 3.983 0 00-1.172-2.828 1 1 0 010-1.415z" clip-rule="evenodd" /> </svg></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> muteIcon <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132"> <path fill-rule="evenodd" d="M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM12.293 7.293a1 1 0 011.414 0L15 8.586l1.293-1.293a1 1 0 111.414 1.414L16.414 10l1.293 1.293a1 1 0 01-1.414 1.414L15 11.414l-1.293 1.293a1 1 0 01-1.414-1.414L13.586 10l-1.293-1.293a1 1 0 010-1.414z" clip-rule="evenodd" /> </svg></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></code></pre></div><p>This will add a <code class="language-text">soundButton</code> variable, which will be the sound button element. It will also create two variables <code class="language-text">soundIcon</code> and <code class="language-text">muteIcon</code> to be used to change the icon of the button based on whether the audio is muted or not.</p><p>Next, add the function which will listen to the click event on the sound button:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">toggleSound</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> audio<span class="token punctuation">.</span>muted <span class="token operator">=</span> <span class="token operator">!</span>audio<span class="token punctuation">.</span>muted<span class="token punctuation">;</span> soundButton<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> audio<span class="token punctuation">.</span>muted <span class="token operator">?</span> muteIcon <span class="token operator">:</span> soundIcon<span class="token punctuation">;</span> <span class="token punctuation">}</span> soundButton<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> toggleSound<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h3 id="final-demo">Final Demo</h3><p>This will be the final result of creating the custom audio player:</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_XWgbGBN" src="https://codepen.io/shahednasser/embed/preview/XWgbGBN?default-tabs=js%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=XWgbGBN" title="Audio Custom Style" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"/></figure><p>The player can play, pause, seek, mute and unmute the audio, all while looking great.</p><h2 id="conclusion">Conclusion</h2><p>Using the pseudo-element selectors, you can do simple design changes to the audio element. </p><p>For more complex design changes, it's best to implement a custom audio player, then bind it with Javascript to the audio element to provide the necessary functionalities.</p>]]></content:encoded></item><item><title><![CDATA[Why Getting Good grades In academics is Really Important?]]></title><description><![CDATA[Grades do matters and good grades will lead us to first-class universities, first-class colleges, and job applications which concludes our future success.]]></description><link>https://blog.shahednasser.com/why-getting-good-grades-in-academic-is-really-important/</link><guid isPermaLink="false">Ghost__Post__612b93c82f96720ecb595f52</guid><category><![CDATA[Education]]></category><dc:creator><![CDATA[Pratibha Singh]]></dc:creator><pubDate>Sun, 29 Aug 2021 14:20:53 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/e7c1a57b9fac0ae2f291f28cc3ad4db1/kimberly-farmer-lUaaKCUANVI-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/e7c1a57b9fac0ae2f291f28cc3ad4db1/kimberly-farmer-lUaaKCUANVI-unsplash-2.jpg" alt="Why Getting Good grades In academics is Really Important?"/><p>When did you last had a talk with your parents regarding grades?</p><p>It’s a quite common topic for a conversation to happen in every household regarding grades.</p><p>And yes, it’s good to talk with your teen but discussing the disadvantages and scary tactics of not getting decent grades such as, “you’ll never get into a good college unlike your friends”, “you’ll never get a decent job to survive” is quite tempting and leaves a negative impression on teens.</p><p><em>What will happen if we get superior grades? Are these grades ever going to help us?</em></p><p>The answer is obviously a big ‘yes’.</p><p>I’ve heard many people saying grades don’t matter and also “a single sheet of paper cannot decide your future”. Make sure you score maximum grades before saying this.</p><p>Grades do matters and good grades will lead us to first-class universities, first-class colleges, and job applications which concludes our future success.</p><p><em>Still not convinced about the great role that grades play in determining your success?</em></p><p>After reading the 5 reasons given below, You will realize that you have been living in the myth for these years, giving a blindfold to your academic performance. Don’t miss the last one.</p><p>“Looking for <a href="https://assignmentxp.com/">Programming Help</a>”? Contact <a href="http://AssignmentXp.com">AssignmentXp.com</a> and they have experts available 24*7 to provide any kind of assistance regarding the programming.</p><p>Here are the 5 reasons why grades are important</p><h2 id="better-opportunities-are-always-ready-to-knock-on-your-door">Better Opportunities Are Always Ready to Knock on Your Door.</h2><p><em>Let</em>’<em>s go back to our school days!!!!</em></p><p>Talking about school life, I don’t know about others but mine was in such a way where students who study better, who score better grades are always provided with different scholarships, rewards in terms of compliments, they get a chance to go on educational trips so that they always stay motivated and do better in the academics.</p><p>Teachers too directly or indirectly tend to focus more on studious kids and personally tell them about other opportunities. Teachers are more friendly with such people and often treats them more adequately.</p><p>In our education system, success is often measured by grades. Grades are important at every step from getting admission to good colleges or universities, to getting a decent job for succeeding.</p><h2 id="better-colleges-are-ready-to-welcome-you">Better Colleges Are Ready to Welcome You</h2><p>Ever thought of getting admission to one of the world’s best universities?</p><p>Better grades grant admissions in a reputed academic college, and academic success at the finest universities leads to a high-paying job that will fulfill your as well as your family’s needs including high bank balance, social status, a big house, exotic vacations, and many more.</p><p>Especially, if you wish to pursue higher professional courses such as law firm, engineering, veterinary studies, MBA, CA, CFA, etc even greater significance is placed on grades. Your GPA score is of utmost importance for your admission to renowned colleges.</p><p>Good colleges not only guarantee academic excellence but also plays a great role in a child’s holistic development. They believe in practicality and prepare students not only for the board exams but also for the exams that the students are going to face in the future.</p><h2 id="better-grades-cause-no-stress">Better Grades Cause No Stress</h2><p>If you get better grades in your examination will there be any other kind of stress??</p><p>Well, according to my it’s a big ‘No’. on the other hand, it feels so good seeing my parents proud of me. It feels so wonderful when your friend’s parents compare you with their child in the parent-teacher meeting. Let me share with you my experience, when I was unable to get better grades compared to my classmates, I was so embarrassed and stressed out that I started overthinking. And…..</p><p>“Stress comes from ignoring stuff that shouldn’t be ignored.”</p><p>I gave more importance to other things rather than my studies and simply for that reason I was surrounded by the dark clouds of stress and anxiety. seeing others getting complimented by teachers in front of the whole class and me sitting with others clapping for my friend’s achievement made me sad.</p><p>As soon as I realized I started studying harder and gradually my grades improved and seeing those grades my stress was relieved and I felt relaxed.</p><h2 id="better-grades-attract-employers">Better Grades Attract Employers</h2><p>College is the closest thing to the professional or the business world that we young people experience and how well we perform there indicates our performance in our job life.</p><p>According to employment recruiters, a student with a better GPA score shows that the given candidate can focus on tasks, handle pressure, learn quickly, and is motivated to succeed. And these are the qualities that the job recruiters are searching for and it is a safe bet to elect candidates with these qualities.</p><h2 id="good-grades-boost-your-confidence">Good Grades Boost Your Confidence</h2><p>Teens sometimes are afraid to try hard because they’re afraid of failure and hence they give up and never try. What’s there to be afraid of? Always remember one thing,</p><p>“You try, you fail, congratulations many people don’t even try”</p><p>Just give your best and you will see the results. And that will surely motivate you to perform better the next time to keep up your good work. It will bring confidence in you and you’ll be able to take up more challenges in your academics.</p><h2 id="good-grades-provide-you-with-a-scholarship">Good Grades Provide You With a Scholarship</h2><p><em>Getting a scholarship is of great honor, isn</em>’<em>t it? have you ever been selected for the scholarship exam?</em></p><p>we always felt jealous seeing our classmate getting selected for scholarship exams, receiving a scholarship doesn’t matter just being selected for scholarship exams makes us feel proud.</p><p>Students these days should get guidance about the advantages and opportunities of getting scholarships so that they perceive it hard to achieve the same.</p><p>Better grades, higher test scores, excellent behavior, involvement in other curricular activities, clubs, honor societies, attracts special funding, and scholarships from various organizations.</p><p>scholarships can be of great help for financially backward students wishing to pursue higher studies and can also be a great help to pay off student loans. Wait, wait……</p><p><em>Don</em>’<em>t feel tensed if you score average.</em></p><p>we always felt jealous seeing our classmate getting selected for scholarship exams, receiving a scholarship doesn’t matter just being selected for scholarship exams makes us feel proud.</p><p>Students these days should get guidance about the advantages and opportunities of getting scholarships so that they perceive it hard to achieve the same.</p><p>Better grades, higher test scores, excellent behavior, involvement in other curricular activities, clubs, honor societies, attracts special funding, and scholarships from various organizations.</p><p>scholarships can be of great help for financially backward students wishing to pursue higher studies and can also be a great help to pay off student loans.</p><p>I understand, many pupils after reading the advantages of better grades will become quite nervous if you are an average scorer. Every finger of your hand can’t be equal and hence no one can be perfect in everything.</p><p>Don’t compare yourself with your friends but with the old you. And, doing everything is of no use, but excelling in one of them is quite important.</p><p>okay so,</p><p>Every person in this universe is either gonna become an employer or an employee. That is you are either gonna work for someone or make someone work, isn’t it?</p><p>If you are dreaming to work in one of the MNC’s ( Microsoft, Nokia Corporation, Reebok International Limited, etc) out there, your GPA (grade point average)score in your resume will be your biggest factor for getting selected as employers there are looking for students who can quietly follow their directions and deliver exactly what is expected from them.</p><p>On the other hand, the criteria for enlisting candidates in Indian Companies include a child’s non-cognitive skills such as problem-solving skills, leadership qualities, oral communication. Of course, grades matter but it’s not the only factor that will decide your selection.</p><p>now comparing both the cases, If you had always had a dream to work in one of those MNC’s out there, don’t let your grades take you downwards and study so hard that people think you are crazy</p><p>But if you are blessed with some of the non-cognitive skills, Indian companies would be a better option to go with. If you are an average scorer but have great debating skills, communication skills, keep participating in all sorts of competitions held on your campus. Take up various public speaking sessions and work on your soft skills. The majority of the students reading this blog don’t have an idea of what they are going to do in the future and hence this question often annoys us.</p><p>“<em>What are your future goals?” they will always end up saying that they</em>’<em>ve not yet decided</em>.</p><p>But however one day you will get married, have a wife, a child, or children. You wish to live a decent life, give your family all the luxuries that you never received in your childhood. At that time you will wish that you would’ve made enough money and had a better job.</p><p>Ok, let’s leave that and think about the present. Don’t you have your dreams of owning a Mercedes, residing in a bungalow with a swimming pool, wearing custom-made suits and expensive watches? just thinking about them makes you smile brightly but the very next second your smile disappears thinking you can’t probably achieve it.</p><p>You can, but for that, you need to make preparations from now, you have to study well and give your everything in academics and make sure that I have to achieve all those dreams that I dreamt of as a child. Studying is only for a limited period, but what you’re going to enjoy will be lifetime enjoyment. So why not sacrifice a bit more for your comfortable future?</p><p>This article is especially for generation Z who are enjoying giving exams online. it has almost been a year and teachings are done through online means. I clearly understand that our teaching was transferred from offline to online in no time. Not only teaching but exams too. Students don’t understand online teachings even though teachers are trying their level best.</p><p><em>The question is why??</em></p><p>Why are we not able to understand anything? It is pretty simple that we are just scrolling Instagram during our lectures or simply just ignoring our classes. Isn’t it guys?</p><p>That’s something that most of the students do. And now when the exams are conducted we simply google the answers. I can surely say that 95% of the students do this and get better grades.</p><p>But are these grades going to help you? Will these grades satisfy you?</p><p>No, right? When everything’s back to normal and schools reopen, exams will be conducted offline and you will then realize that you lost your concentration in your studies because you didn’t study at all</p><p>Don’t mind what I said but that’s the fact!! You can change even now there’s still time left. Avoid things that distract you from your studies. Start gaining your concentration again.</p>]]></content:encoded></item><item><title><![CDATA[How to Use MongoDB With Laravel]]></title><description><![CDATA[In this tutorial, we'll learn how to integrate MongoDB with Laravel. We'll create a simple blog with authentication and posts management.]]></description><link>https://blog.shahednasser.com/how-to-use-mongodb-with-laravel/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ec0</guid><category><![CDATA[Laravel]]></category><category><![CDATA[MongoDB]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 26 Aug 2021 06:49:39 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/68cf050879e04ae26b89b493169c4a81/mohammad-rahmani-Y5yxdx2a4PI-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/68cf050879e04ae26b89b493169c4a81/mohammad-rahmani-Y5yxdx2a4PI-unsplash-2.jpg" alt="How to Use MongoDB With Laravel"/><p><a href="https://laravel.com">Laravel</a> is a popular PHP framework that has been around for a long time now. With Laravel, you can easily build web apps, APIs, and more.</p><p><a href="https://www.mongodb.com">MongoDB</a> is a popular NoSQL database that has also been popular for a while now. With MongoDB, you can build databases that are collections of JSON-like documents.</p><p>Laravel is usually used with relational databases like MySQL and provides easy interfaces, facades, and methods to access, insert, update and delete the data in it.</p><p>Laravel does not come with native support for MongoDB. In order to use MongoDB with Laravel, some configurations and libraries are required to successfully integrate the two.</p><p>In this tutorial, we'll learn how to integrate MongoDB with Laravel. We'll create a simple blog with authentication and posts management.</p><p>You can find the code for this tutorial on <a href="https://github.com/shahednasser/laravel-mongodb-tutorial">this GitHub Repository</a>.</p><h2 id="prerequisites">Prerequisites</h2><h3 id="required">Required</h3><p>Before going through the tutorial, make sure you have the following installed on your machine:</p><ul><li><a href="https://www.php.net/downloads.php">PHP</a> >= 7.3</li><li><a href="https://getcomposer.org/download/">Composer</a></li><li><a href="https://www.mongodb.com/try/download/community">MongoDB</a></li></ul><p>In addition, you need to install <a href="https://docs.mongodb.com/drivers/php/">MongoDB's PHP extension</a>. You can do so with the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">pecl <span class="token function">install</span> mongodb</code></pre></div><p>If you're running on a Mac OS with Apple M1 and you get an error about <code class="language-text">pcre2.h</code>, run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">cp</span> /opt/homebrew/Cellar/pcre2/10.36/include/pcre2.h /opt/homebrew/Cellar/php<span class="token punctuation">\</span>@7.*/7.*.*/include/php/ext/pcre/pcre2.h</code></pre></div><p>Where <code class="language-text">7.*</code> and <code class="language-text">7.*.*</code> depend on your PHP version installed.</p><p>These dependencies are essential for development. So, make sure you have them all installed.</p><h3 id="optional">Optional</h3><p>The following are not required, but are optional to be able to follow with the article:</p><ul><li><a href="https://nodejs.org/en/">Node.js</a></li><li><a href="https://blog.shahednasser.com/use-mingo-to-easily-manage-your-mongodb-databases/">Mingo</a>, a software that allows you to easily manage and view the MongoDB databases on a server.</li></ul><h2 id="create-laravel-website">Create Laravel Website</h2><p>In your terminal, run the following command to create a new Laravel website:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">composer</span> create-project laravel/laravel laravel-mongodb</code></pre></div><p>Then, change to the directory of the website you just created:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> laravel-mongodb</code></pre></div><p>Try to start the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan serve</code></pre></div><p>If everything is ok, the website will be available at <code class="language-text">localhost:8000</code>.</p><h2 id="install-integration-library">Install Integration Library</h2><p>In order to integrate MongoDB with Laravel, we need to use the package <a href="https://github.com/jenssegers/laravel-mongodb">jenssegers/mongodb</a>. So, we'll install it with Composer:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">composer</span> require jenssegers/mongodb</code></pre></div><h2 id="configure-the-connection">Configure the Connection</h2><p>After installing the library, we need to configure the connection to our MongoDB server.</p><p>Make sure that your MongoDB server is running. Then, go to <code class="language-text">.env</code> in your Laravel project and update the following keys:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">DB_CONNECTION=mongodb DB_HOST=127.0.0.1 DB_PORT=27017 DB_DATABASE=blog DB_USERNAME= DB_PASSWORD=</code></pre></div><p>Notice that we're using the default values for <code class="language-text">DB_HOST</code> and <code class="language-text">DB_PORT</code> for a local MongoDB server. </p><p>Make sure to add <code class="language-text">DB_USERNAME</code> and <code class="language-text">DB_PASSWORD</code> based on your MongoDB username and password. If you don't have any, then you can leave it empty.</p><p>Next, open <code class="language-text">config/database.php</code> and add the following inside the array of the <code class="language-text">connections</code> key:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token string single-quoted-string">'connections'</span> <span class="token operator">=></span> <span class="token punctuation">[</span> <span class="token operator">...</span><span class="token operator">.</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'mongodb'</span> <span class="token operator">=></span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'mongodb'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'host'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'DB_HOST'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'127.0.0.1'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'port'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'DB_PORT'</span><span class="token punctuation">,</span> <span class="token number">27017</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'database'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'DB_DATABASE'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'blog'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'username'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'DB_USERNAME'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'password'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'DB_PASSWORD'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">)</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div><p>That's all that we need to do to create the connection between MongoDB and Laravel.</p><p>To test it out, we can migrate the default migrations that come with a Laravel project and see if the database will be created in MongoDB:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan migrate</code></pre></div><p>If the connection was done correctly, the migrations will run successfully with no errors.</p><p>To check that the database and collections have been created successfully, you can go to your MongoDB server whether by using the command line/terminal or using a GUI like <a href="https://blog.shahednasser.com/use-mingo-to-easily-manage-your-mongodb-databases/">Mingo</a>. You'll see that the database has been created successfully with the necessary collections.</p><h2 id="change-the-models">Change the Models</h2><p>By default, Laravel uses <a href="https://laravel.com/docs/8.x/eloquent">Eloquent</a> for all its models. As Eloquent does not support MongoDB, we need to change the class that our models extend. The class is provided from the package <code class="language-text">jenssegers/mongodb</code> that we installed earlier. It allows us to use our models and access data just like we would when using MySQL or other supported databases.</p><p>Currently, we only have one model, which is the <code class="language-text">User</code> model. Go to <code class="language-text">app/Models/User.php</code> and change the class it extends by changing the <code class="language-text">Authenticatable</code> class used at the beginning of the file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">use</span> <span class="token package">Jenssegers<span class="token punctuation">\</span>Mongodb<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>User</span> <span class="token keyword">as</span> Authenticatable<span class="token punctuation">;</span></code></pre></div><p>As the <code class="language-text">User</code> is a model that can undergo authentication like registering and logging in, it should extend <code class="language-text">Jenssegers\Mongodb\Auth\User</code>.</p><p>The next change we need to make is related to casting dates. In order to use dates as Carbon objects, add the following inside the <code class="language-text">User</code> class:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"> <span class="token comment">/** * The attributes that should be cast to native types. * * @var array */</span> <span class="token keyword">protected</span> <span class="token variable">$dates</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'email_verified_at'</span><span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre></div><p>That's all that is required to make a model compatible with both Laravel's Eloquent and MongoDB. We'll see in the next sections how we can access, add, modify and delete the data.</p><h2 id="add-authentication">Add Authentication</h2><p>We'll add authentication to our website to allow users to register and log in. To do this and save time on creating the authentication forms and routes, we'll use <a href="https://laravel.com/docs/8.x/starter-kits#laravel-breeze">Laravel's Breeze</a>.</p><p>Breeze provides sleek-looking authentication forms using <a href="https://tailwindcss.com">Tailwind CSS</a> and <a href="https://alpinejs.dev">AlpineJS</a>. You don't need to know either to go through the tutorial.</p><p>The next few parts of the tutorial that are related to installing and configuring Breeze are optional. If you're not interested in following this part of the tutorial you can skip it.</p><h3 id="install-breeze">Install Breeze</h3><p>First, we'll install Breeze:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan breeze:install</code></pre></div><p>Then, we need to install the required NPM dependencies and compile the Breeze assets:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token operator">&&</span> <span class="token function">npm</span> run dev</code></pre></div><p>That's it! Now, we'll have nice-looking authentication forms and routes.</p><h3 id="testing-authentication">Testing Authentication</h3><p>Start the server if it isn't already started and go to <code class="language-text">localhost:8000/register</code>. You'll see a registration form that includes the basic user fields required by default in Laravel.</p><p>Try creating a user. You'll then be redirected to <code class="language-text">localhost:8000/dashboard</code>, which is the default in Breeze.</p><h3 id="changing-default-route">Changing Default Route</h3><p>By default, Breeze redirects authenticated users to the route <code class="language-text">/dashboard</code>. We'll change it to the home page.</p><p>Go to <code class="language-text">routes/web.php</code> and change the content to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">PostController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'home'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'auth'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Now, when the user goes to <code class="language-text">localhost:8000</code> and they're not logged in, they will be redirected to the sign-in form. If they're logged in, they can access the blog.</p><p>Next, create the controller that will handle this request:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan make:controller PostController</code></pre></div><p>Inside the controller, add the following method:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">home</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will just return the view <code class="language-text">home</code>. This view is actually now named <code class="language-text">dashboard.blade.php</code> and it's in <code class="language-text">resources/views</code>. So, rename it to <code class="language-text">home.blade.php</code>.</p><p>Then, change the link for the home page in the navigation by replacing <code class="language-text">route('dashboard')</code> in <code class="language-text">resources/views/layouts/navigation.blade.php</code> with <code class="language-text">route('home')</code> everywhere it's used. Additionally, replace texts that have <code class="language-text">Dashboard</code> in them with <code class="language-text">Home</code>.</p><p>Finally, change the route that should be redirected to when the user is authenticated in <code class="language-text">app/Providers/RouteServiceProvider.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">const</span> <span class="token constant">HOME</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'/'</span><span class="token punctuation">;</span></code></pre></div><p>If you try to access the website on <code class="language-text">localhost:8000</code>, if you're still logged in you'll see the page we saw earlier after signing up. </p><h2 id="implement-crud-operations">Implement CRUD Operations</h2><p>In this section, we'll see how to create a new model that's compatible with MongoDB and perform Create, Read, Update and Delete (CRUD) operations.</p><h3 id="create-the-migration">Create the Migration</h3><p>First, create the migration which will create a new <code class="language-text">posts</code> collection in the database:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan make:migration create_posts_table</code></pre></div><p>This will create the migration file <code class="language-text">database/migration/YEAR_MONTH_DAY_TIME_create_posts_table</code>, where <code class="language-text">YEAR</code>, <code class="language-text">MONTH</code>, <code class="language-text">DAY</code>, and <code class="language-text">TIME</code> depend on when you create this migration.</p><p>Open the file and inside the <code class="language-text">up</code> method, change the code to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Schema</span><span class="token operator">::</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'posts'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Blueprint</span> <span class="token variable">$table</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$table</span><span class="token operator">-></span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$table</span><span class="token operator">-></span><span class="token keyword type-declaration">string</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'title'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$table</span><span class="token operator">-></span><span class="token function">longText</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$table</span><span class="token operator">-></span><span class="token function">foreignId</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'user_id'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">constrained</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'users'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cascadeOnDelete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cascadeOnUpdate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$table</span><span class="token operator">-></span><span class="token function">timestamps</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This will create a collection where documents inside will have the fields <code class="language-text">_id</code>, <code class="language-text">title</code>, <code class="language-text">content</code>, <code class="language-text">user_id</code> which will act as a foreign key towards the <code class="language-text">users</code> table, and timestamps fields like <code class="language-text">created_at</code> and <code class="language-text">updated_at</code>.</p><p>Run the following to execute the migration:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan migrate</code></pre></div><p>This will add a new collection <code class="language-text">posts</code> in your database.</p><h3 id="create-the-model">Create the Model</h3><p>Next, we'll create the <code class="language-text">Post</code> model for the <code class="language-text">posts</code> table. Run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan make:model Post</code></pre></div><p>As we did with the <code class="language-text">User</code> model, we need to change the class the model extends. For <code class="language-text">User</code>, we used <code class="language-text">Jenssegers\Mongodb\Auth\User</code> as the model was authenticatable.</p><p>The <code class="language-text">Post</code> model is not authenticatable. So, it will just extend the class <code class="language-text">Jenssegers\Mongodb\Eloquent\Model</code>.</p><p>At the beginning of <code class="language-text">app/Models/Post.php</code> change the class <code class="language-text">Model</code> used to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">use</span> <span class="token package">Jenssegers<span class="token punctuation">\</span>Mongodb<span class="token punctuation">\</span>Eloquent<span class="token punctuation">\</span>Model</span><span class="token punctuation">;</span></code></pre></div><p>Inside the class, add the following to define the model's fields:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">protected</span> <span class="token variable">$fillable</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'title'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'content'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'user_id'</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">protected</span> <span class="token variable">$dates</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'created_at'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'updated_at'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">user</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">belongsTo</span><span class="token punctuation">(</span><span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>We have set the fillable fields to be <code class="language-text">title</code>, <code class="language-text">content</code>, and <code class="language-text">user_id</code>. We've also set the dates to be <code class="language-text">created_at</code> and <code class="language-text">updated_at</code>. Finally, we've added a <code class="language-text">belongsTo</code> relationship between <code class="language-text">Post</code> and <code class="language-text">User</code>.</p><h3 id="show-posts">Show Posts</h3><p>We'll add a blade component that will be used to display posts. Create the file <code class="language-text">resources/views/components/post.blade.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"bg-white overflow-hidden shadow-sm sm:rounded-lg"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"p-6 bg-white border-b border-gray-200"</span><span class="token operator">></span> <span class="token operator"><</span>h1 <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"text-xl md:text-2xl"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'title'</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>p <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"my-2"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator"><</span>small <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"text-gray-500"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'user'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'name'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">-</span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'created_at'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>small<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></code></pre></div><p>We're just showing the title, content, name of the user, and the date the post is created.</p><p>Next, we'll change the home page to display all posts, if there are any.</p><p>Go to <code class="language-text">resources/views/home.blade.php</code> and change the content to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>x<span class="token operator">-</span>app<span class="token operator">-</span>layout<span class="token operator">></span> <span class="token operator"><</span>x<span class="token operator">-</span>slot name<span class="token operator">=</span><span class="token string double-quoted-string">"header"</span><span class="token operator">></span> <span class="token operator"><</span>h2 <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"font-semibold text-xl text-gray-800 leading-tight"</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Home'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>x<span class="token operator">-</span>slot<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"py-12"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"max-w-7xl mx-auto sm:px-6 lg:px-8"</span><span class="token operator">></span> @<span class="token keyword">empty</span><span class="token punctuation">(</span><span class="token variable">$posts</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"bg-white overflow-hidden shadow-sm sm:rounded-lg"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"p-6 bg-white border-b border-gray-200"</span><span class="token operator">></span> There are no posts <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @endempty @<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$posts</span> <span class="token keyword">as</span> <span class="token variable">$post</span><span class="token punctuation">)</span> @<span class="token function">component</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'components.post'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'post'</span> <span class="token operator">=></span> <span class="token variable">$post</span><span class="token punctuation">]</span><span class="token punctuation">)</span> @endcomponent @<span class="token keyword">endforeach</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>x<span class="token operator">-</span>app<span class="token operator">-</span>layout<span class="token operator">></span></code></pre></div><p>Now, if there are any posts, they'll be each displayed as cards. If there aren't any, the message "There are no posts" will be shown.</p><p>Finally, we need to pass the <code class="language-text">$posts</code> variable from the controller to the view. Change the <code class="language-text">home</code> method to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">home</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$posts</span> <span class="token operator">=</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token function">with</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'user'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'posts'</span> <span class="token operator">=></span> <span class="token variable">$posts</span><span class="token operator">-></span><span class="token function">toArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>We are able to read data from our MongoDB database the same way we would with the MySQL database, using the same Eloquent methods.</p><p>If you try opening the blog now, you'll see that the message "there are no posts is showing."</p><h3 id="create-and-update-a-post">Create and Update a Post</h3><p><strong>Create Post</strong></p><p>We'll create a form that allows the logged-in user to create a post.</p><p>First, add the route in <code class="language-text">web/routes.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts/create'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">PostController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'createForm'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'auth'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post.form'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Then, add the <code class="language-text">createForm</code> method in <code class="language-text">PostController</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">createForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post_form'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Finally, create the view file <code class="language-text">resources/view/post_form.blade.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>x<span class="token operator">-</span>app<span class="token operator">-</span>layout<span class="token operator">></span> <span class="token operator"><</span>x<span class="token operator">-</span>slot name<span class="token operator">=</span><span class="token string double-quoted-string">"header"</span><span class="token operator">></span> <span class="token operator"><</span>h2 <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"font-semibold text-xl text-gray-800 leading-tight"</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token keyword">isset</span><span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Edit Post'</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token class-name return-type">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Create Post'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>x<span class="token operator">-</span>slot<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"py-12"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"max-w-7xl mx-auto sm:px-6 lg:px-8"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"bg-white overflow-hidden shadow-sm sm:rounded-lg"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"p-6 bg-white border-b border-gray-200"</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">!</span><span class="token operator">--</span> Session Status <span class="token operator">--</span><span class="token operator">></span> <span class="token operator"><</span>x<span class="token operator">-</span>auth<span class="token operator">-</span>session<span class="token operator">-</span>status <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-4"</span> <span class="token punctuation">:</span>status<span class="token operator">=</span><span class="token string double-quoted-string">"session('status')"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">!</span><span class="token operator">--</span> Validation Errors <span class="token operator">--</span><span class="token operator">></span> <span class="token operator"><</span>x<span class="token operator">-</span>auth<span class="token operator">-</span>validation<span class="token operator">-</span>errors <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-4"</span> <span class="token punctuation">:</span>errors<span class="token operator">=</span><span class="token string double-quoted-string">"<span class="token interpolation"><span class="token variable">$errors</span></span>"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>form method<span class="token operator">=</span><span class="token string double-quoted-string">"POST"</span> action<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('post.save') }}"</span><span class="token operator">></span> @csrf @<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">isset</span><span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"hidden"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"id"</span> value<span class="token operator">=</span><span class="token string double-quoted-string">"{{ <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">_id</span></span> }}"</span> <span class="token operator">/</span><span class="token operator">></span> @<span class="token keyword">endif</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>x<span class="token operator">-</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"title"</span> <span class="token punctuation">:</span>value<span class="token operator">=</span><span class="token string double-quoted-string">"__('Title')"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>x<span class="token operator">-</span>input id<span class="token operator">=</span><span class="token string double-quoted-string">"title"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"block mt-1 w-full"</span> type<span class="token operator">=</span><span class="token string double-quoted-string">"text"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"title"</span> <span class="token punctuation">:</span>value<span class="token operator">=</span><span class="token string double-quoted-string">"old('title') ?: (isset(<span class="token interpolation"><span class="token variable">$post</span></span>) ? <span class="token interpolation"><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">title</span></span> : '')"</span> required autofocus <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mt-3"</span><span class="token operator">></span> <span class="token operator"><</span>x<span class="token operator">-</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"content"</span> <span class="token punctuation">:</span>value<span class="token operator">=</span><span class="token string double-quoted-string">"__('Content')"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>textarea id<span class="token operator">=</span><span class="token string double-quoted-string">"content"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"content"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"block mt-1 w-full rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"</span> rows<span class="token operator">=</span><span class="token string double-quoted-string">"5"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">old</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">)</span> <span class="token operator">?</span><span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token keyword">isset</span><span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">content</span> <span class="token punctuation">:</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>textarea<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"flex items-center justify-end mt-4"</span><span class="token operator">></span> <span class="token operator"><</span>x<span class="token operator">-</span>button<span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Save'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>x<span class="token operator">-</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>x<span class="token operator">-</span>app<span class="token operator">-</span>layout<span class="token operator">></span></code></pre></div><p>Note that we're making the form ready for editing as well (which we'll go over later). The form has 2 fields, <code class="language-text">title</code> and <code class="language-text">content</code>.</p><p>Our form is now ready, the last thing we need to do is add a link to it in the navigation bar. In <code class="language-text">resources/views/layouts/navigation.blade.php</code> add the following under the link for "Home":</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>x<span class="token operator">-</span>nav<span class="token operator">-</span>link <span class="token punctuation">:</span>href<span class="token operator">=</span><span class="token string double-quoted-string">"route('post.form')"</span> <span class="token punctuation">:</span>active<span class="token operator">=</span><span class="token string double-quoted-string">"request()->routeIs('post.form')"</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Create Post'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>x<span class="token operator">-</span>nav<span class="token operator">-</span>link<span class="token operator">></span></code></pre></div><p>If you go on the website now, you'll see a new link in the navigation bar for "Create Post".</p><p>Go to that page. You'll see the form we created which has the 2 fields we mentioned.</p><p>Next, we need to implement the post method that will handle saving the post. </p><p>In <code class="language-text">routes/web.php</code>, add the following new route:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts/create'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">PostController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'save'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'auth'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post.save'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Then, add the <code class="language-text">save</code> method in <code class="language-text">PostController</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">save</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name static-context">Validator</span><span class="token operator">::</span><span class="token function">validate</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'id'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'nullable|exists:posts,_id'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'title'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'required|min:1'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'content'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'required|min:1'</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/** @var User $user */</span> <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$id</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$post</span> <span class="token operator">=</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">find</span><span class="token punctuation">(</span><span class="token variable">$id</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token property">_id</span> <span class="token operator">!==</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">_id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token variable">$post</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Post</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">associate</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">title</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'title'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">content</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>In this method, we're first validating the fields that are required, which are <code class="language-text">title</code> and <code class="language-text">content</code>. We're also validating <code class="language-text">id</code> which will be passed only when the post is being edited. So, it can be nullable, but when it's available, it should exist in the <code class="language-text">posts</code> collection in the field <code class="language-text">_id</code>.</p><p>Suggested Read: <a href="https://blog.shahednasser.com/beginners-guide-to-validation-in-laravel/">Beginner’s Guide to Validation in Laravel</a></p><p>Next, if the post is being edited, we're validating that the user editing this post is actually the user that created it. The post's user can be easily accessed through the relationship we defined in the class.</p><p>Finally, we're creating or updating the post, setting the title, content, and user creating it. Then, we redirect back home.</p><p>You can now try adding a post. Open the form and enter a title and content, then click Save. If everything is done correctly, you'll be redirected to the home page and you can see the new post added.</p><p>You can also check on your MongoDB server if the new post has been added successfully.</p><p><strong>Edit Post</strong></p><p>As mentioned earlier, the form is ready to be used for editing a post. </p><p>We'll add an edit button for posts that will allow the user to edit a post.</p><p>First, create the file <code class="language-text">resources/views/components/edit.blade.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>svg xmlns<span class="token operator">=</span><span class="token string double-quoted-string">"http://www.w3.org/2000/svg"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"h-6 w-6"</span> fill<span class="token operator">=</span><span class="token string double-quoted-string">"none"</span> viewBox<span class="token operator">=</span><span class="token string double-quoted-string">"0 0 24 24"</span> stroke<span class="token operator">=</span><span class="token string double-quoted-string">"currentColor"</span><span class="token operator">></span> <span class="token operator"><</span>path stroke<span class="token operator">-</span>linecap<span class="token operator">=</span><span class="token string double-quoted-string">"round"</span> stroke<span class="token operator">-</span>linejoin<span class="token operator">=</span><span class="token string double-quoted-string">"round"</span> stroke<span class="token operator">-</span>width<span class="token operator">=</span><span class="token string double-quoted-string">"2"</span> d<span class="token operator">=</span><span class="token string double-quoted-string">"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>svg<span class="token operator">></span></code></pre></div><p>This component is just an edit icon from <a href="https://heroicons.com">Heroicons</a>.</p><p>Now, we'll use this icon to add an edit button. Change <code class="language-text">resources/views/components/post.blade.php</code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"bg-white overflow-hidden shadow-sm sm:rounded-lg"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"p-6 bg-white border-b border-gray-200"</span><span class="token operator">></span> <span class="token operator"><</span>h1 <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"text-xl md:text-2xl"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'title'</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>p <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"my-2"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'content'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator"><</span>small <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"text-gray-500"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'user'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'name'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">-</span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'created_at'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>small<span class="token operator">></span> @<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token property">_id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'user'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'_id'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator"><</span>a href<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('post.edit.form', ['id' => <span class="token interpolation"><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'_id'</span><span class="token punctuation">]</span></span>]) }}"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"inline-block align-middle pb-1 text-decoration-none text-gray-600"</span><span class="token operator">></span> @<span class="token function">component</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'components.edit'</span><span class="token punctuation">)</span> @endcomponent <span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> @<span class="token keyword">endif</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></code></pre></div><p>This will add the link to edit the post only when the post belongs to the current user. </p><p>Next, add a new route to go to the form and edit the post:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts/{id}/edit'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">PostController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'editForm'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'auth'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post.edit.form'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Finally, add the method <code class="language-text">editForm</code> in <code class="language-text">PostController</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">editForm</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token variable">$id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$post</span> <span class="token operator">=</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">find</span><span class="token punctuation">(</span><span class="token variable">$id</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post_form'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'post'</span> <span class="token operator">=></span> <span class="token variable">$post</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>That's all we need to add to be able to edit a post. Try opening the website and clicking on the edit icon for any of the posts. It will take you to the same post form, but with the values filled.</p><p>Try making edits to the post and click save. You'll be redirected to the home page and you can see the post has been updated.</p><h3 id="delete-post">Delete Post</h3><p>The last thing we need to add is the ability to delete a post.</p><p>Create the file <code class="language-text">resources/views/components/delete.blade.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>svg xmlns<span class="token operator">=</span><span class="token string double-quoted-string">"http://www.w3.org/2000/svg"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"h-6 w-6"</span> fill<span class="token operator">=</span><span class="token string double-quoted-string">"none"</span> viewBox<span class="token operator">=</span><span class="token string double-quoted-string">"0 0 24 24"</span> stroke<span class="token operator">=</span><span class="token string double-quoted-string">"currentColor"</span><span class="token operator">></span> <span class="token operator"><</span>path stroke<span class="token operator">-</span>linecap<span class="token operator">=</span><span class="token string double-quoted-string">"round"</span> stroke<span class="token operator">-</span>linejoin<span class="token operator">=</span><span class="token string double-quoted-string">"round"</span> stroke<span class="token operator">-</span>width<span class="token operator">=</span><span class="token string double-quoted-string">"2"</span> d<span class="token operator">=</span><span class="token string double-quoted-string">"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>svg<span class="token operator">></span></code></pre></div><p>Similar to the edit button, we're creating a component for a delete icon to use for the button.</p><p>In <code class="language-text">resources/views/components/post.blade.php</code> add the following after the edit link:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>form method<span class="token operator">=</span><span class="token string double-quoted-string">"POST"</span> action<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('post.delete') }}"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"inline-block align-middle"</span><span class="token operator">></span> @csrf <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"hidden"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"id"</span> value<span class="token operator">=</span><span class="token string double-quoted-string">"{{ <span class="token interpolation"><span class="token variable">$post</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'_id'</span><span class="token punctuation">]</span></span> }}"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string double-quoted-string">"submit"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"border-0 bg-transparent text-red-400"</span><span class="token operator">></span> @<span class="token function">component</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'components.delete'</span><span class="token punctuation">)</span> @endcomponent <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span></code></pre></div><p>Now, add a new route in <code class="language-text">routes/web.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts/delete'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">PostController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'delete'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'auth'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'post.delete'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Finally, create the <code class="language-text">delete</code> method in <code class="language-text">PostController</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">delete</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name static-context">Validator</span><span class="token operator">::</span><span class="token function">validate</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'id'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'exists:posts,_id'</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$post</span> <span class="token operator">=</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">find</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'id'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>First, we're validating that the ID is sent in the request and that it's a post that exists. Then, we're deleting the post. </p><p>Notice how to delete we can use the same eloquent methods we use in Laravel.</p><p>For simplicity, we're omitting the validation check to make sure that the post belongs to the logged-in user.</p><p>Go to the home page now. You'll see a delete icon next to each post. Try clicking on one of them. You'll be redirected back to the home page and the post will be deleted.</p><h2 id="conclusion">Conclusion</h2><p>In this tutorial, we were able to connect a Laravel website to a MongoDB server. As we saw, the integration is simple and seamless. </p><p>Even with the integration, you can use Eloquent models like you would when using other supported databases. </p><p>More can be done with <code class="language-text">jenssegers/mongodb</code> package. You can try adding to the website we created a search bar or advanced search with filters. Make sure to check out the documentation of the package, as well.</p>]]></content:encoded></item><item><title><![CDATA[Solve Captcha and reCAPTCHA Challenges with 2Captcha]]></title><description><![CDATA[2Captcha is a captcha solving software that can easily solve many kinds of captchas including Google's reCAPTCHA.]]></description><link>https://blog.shahednasser.com/solve-captcha-and-recaptcha-challenges-with-2captcha/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ebf</guid><category><![CDATA[Reviews]]></category><category><![CDATA[PHP]]></category><category><![CDATA[Laravel]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 23 Aug 2021 08:03:18 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/302c506d78ad889582f21867416b855b/blog.shahednasser.com-4.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/302c506d78ad889582f21867416b855b/blog.shahednasser.com-4.png" alt="Solve Captcha and reCAPTCHA Challenges with 2Captcha"/><p><a href="http://2captcha.com/?utm_medium=content&utm_source=pakainfo&utm_campaign=en">2Captcha</a> is a captcha solving software that allows you to bypass captcha of different types. Using 2Captcha, you'll be able to bypass captcha like Google's reCAPTCHA, TikTok Captcha, FunCaptcha, or just regular text captcha.</p><p>We'll briefly go over what 2Captcha can do and a simple example website to showcase how it can bypass captcha.</p><h2 id="what-are-captchas">What are Captchas</h2><p>When you go on a website and try to submit a form, they often ask you to solve a certain challenge like filling in the words of an image or choosing the image that shows a car among a set of images.</p><p>These types of challenges are what's called a Captcha. Captchas aim to prevent bots from spamming or submitting forms multiple times. Providing random challenges only humans can solve makes it harder for bots to perform a certain action or at least decelerate their speed.</p><h2 id="why-bypass-captchas">Why ByPass Captchas</h2><p>Captcha challenges come in many forms. Before, Captchas mainly consisted of an image with random words or characters that are not easily readable. </p><p>Nowadays, Captchas have evolved to make it harder and harder to be solved by an automated tool.</p><p>Captchas now can be puzzles like rotating an image to its correct angle or even solving a puzzle, which is a challenge provided by <a href="https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwiuxuqZoL3yAhWlEWMBHRWlBkEQFnoECA4QAw&url=https%3A%2F%2Fwww.keycaptcha.com%2F&usg=AOvVaw34DakyjL2uB-lnfcZrSxPc">KeyCAPTCHA</a>.</p><p>All the different captchas, and the different captcha providers, made it harder for bots and automated solving tools to anticipate and solve the captchas a website might have.</p><p>Captcha challenges are not just tough for bots, but sometimes for humans too. A lot of times we can't decipher a challenge and have to click the "try again" button a couple of times.</p><p>It also can be a hindrance when it happens repeatedly. It will slow down our browsing and can be annoying when we continue to fail at the challenge. The harder the captchas are becoming to prevent bots, the harder they're becoming for humans, as well. </p><h2 id="why-2captcha">Why 2Captcha</h2><p>How can you bypass captchas of all kinds and perform a certain action without actually solving the challenge yourself? That's where a captcha solver like 2Captcha comes in.</p><p>2Captcha provides services to solve captchas of different kinds, like Google reCAPTCHA or puzzles from KeyCAPTCHA. Regardless the type of captcha, you can use 2Captcha's services to solve that captcha.</p><h2 id="is-2captcha-reliable">Is 2Captcha Reliable?</h2><p>2Captcha guarantees that all recaptchas can be recognized by its service. As captchas should be readable by humans, 2Captcha employs humans to help train its algorithm and system. For that reason, it's a reliable captcha solving service.</p><p>Not only is it reliable, but it also provides a very affordable plan at $0.5 for every 1000 captchas solved.</p><h2 id="how-can-you-use-2captcha">How Can You Use 2Captcha</h2><p>2Captcha provides a <a href="https://2captcha.com/software/?utm_medium=content&utm_source=pakainfo&utm_campaign=en">variety of free and paid software and services</a> to solve captchas and more.</p><h3 id="api-and-sdk">API and SDK</h3><p>In addition to its easy API, 2Captcha also has SDKs for different programming languages including PHP, Java, Go, and more. This makes its integration in your software easier, as you can easily find SDKs based on the programming language or framework you're using.</p><h3 id="chrome-extension">Chrome Extension</h3><p>2Captcha also offers a <a href="https://chrome.google.com/webstore/detail/2captcha-solver/ifibfemgeogfhoebkmokieepdoobkbpo">free Chrome Extension</a> that will automatically solve a captcha challenge you might see when viewing any page. This makes surfing the web easier and quicker!</p><h2 id="how-to-bypass-captcha">How to Bypass Captcha</h2><p>This section will create a simple website to showcase how 2Captcha can accurately solve a normal text Captcha. This website will be built with Laravel and React.</p><p>We'll go over how to use <a href="https://github.com/2captcha/2captcha-php">2Captcha's PHP SDK</a> as well, which provides easy methods to implement the integration.</p><h3 id="setup-server">Setup Server</h3><p>We'll set up a Laravel server first. Run the following command in your terminal:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">composer</span> create-project laravel/laravel 2captcha-tutorial</code></pre></div><p>Then, change the directory to the created website:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> 2captcha-tutorial</code></pre></div><h3 id="install-dependencies">Install Dependencies</h3><p>Next, we'll install the dependencies we need.</p><p>We'll first install the NPM dependencies required to use React with Laravel:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token function">npm</span> <span class="token function">install</span> react react-dom</code></pre></div><p>To compile our React components, add the following in <code class="language-text">webpack.mix.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">mix<span class="token punctuation">.</span><span class="token function">js</span><span class="token punctuation">(</span><span class="token string">'resources/js/app.js'</span><span class="token punctuation">,</span> <span class="token string">'public/js'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">react</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Then, we'll install 2 Composer packages. We'll install 2Captcha's PHP SDK:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">composer</span> require 2captcha/2captcha</code></pre></div><p>And we'll install <a href="https://github.com/Gregwar/CaptchaBundle">Gregwar's CaptchaBundle</a> to generate a captcha image that we can use to test how 2Captcha solves captchas:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">composer</span> require gregwar/captcha</code></pre></div><h3 id="create-web-page">Create Web Page</h3><p>In this section, we'll create the main web page that will show the captcha image.</p><p>We'll create the controller that will handle the loading of the page and later the solving of the captcha challenge:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan make:controller CaptchaController</code></pre></div><p>Then, go to <code class="language-text">app/Http/Controllers/CaptchaController.php</code> and add the following function inside the class:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">open</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$builder</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CaptchaBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$builder</span><span class="token operator">-></span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$path</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'images/captcha.jpg'</span><span class="token punctuation">;</span> <span class="token variable">$builder</span><span class="token operator">-></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token function"><span class="token punctuation">\</span>public_path</span><span class="token punctuation">(</span><span class="token variable">$path</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'welcome'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'captchaImage'</span> <span class="token operator">=></span> <span class="token variable">$path</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will generate a captcha image and place it in <code class="language-text">public/images</code>, then will send the path of the image to the view.</p><p>Next, change the route handler for the <code class="language-text">/</code> route. Go to <code class="language-text">routes/web.php</code> and change the route currently present:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">CaptchaController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'open'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Now, we'll modify the view of the homepage. Go to <code class="language-text">resources/views/welcome.blade.php</code> and add the Bootstrap CDN in the <code class="language-text"><head></code> to provide styling:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">integrity</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We<span class="token punctuation">"</span></span> <span class="token attr-name">crossorigin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>anonymous<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code></pre></div><p>Then, change the <code class="language-text"><body></code> to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>body <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"container mt-5"</span><span class="token operator">></span> <span class="token operator"><</span>script<span class="token operator">></span> window<span class="token operator">.</span>captchaImage <span class="token operator">=</span> <span class="token string double-quoted-string">"{{ <span class="token interpolation"><span class="token variable">$captchaImage</span></span> }}"</span><span class="token punctuation">;</span> <span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span> <span class="token operator"><</span>div id<span class="token operator">=</span><span class="token string double-quoted-string">"root"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>script src<span class="token operator">=</span><span class="token string double-quoted-string">"/js/app.js"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>body<span class="token operator">></span></code></pre></div><p>This will add the image path we sent from the controller to the <code class="language-text">window</code> object so we can use it later in the React component and adds a <code class="language-text"><div></code> if ID <code class="language-text">root</code> which is where we'll render the React component. Finally, we're placing the Javascript file <code class="language-text">/js/app.js</code> at the end of the body.</p><h3 id="create-react-component">Create React Component</h3><p>Now, we'll create the React component that will show the Captcha image, and when the button Get Value is clicked will get the value from the server.</p><p>Create the file <code class="language-text">resources/js/CaptchaSolver.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">CaptchaSolver</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>captchaValue<span class="token punctuation">,</span> setCaptchaValue<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">function</span> <span class="token function">getCaptchaValue</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>disabled <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> window<span class="token punctuation">.</span>axios<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">'/api/solve'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">image</span><span class="token operator">:</span> window<span class="token punctuation">.</span>captchaImage<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setCaptchaValue</span><span class="token punctuation">(</span>response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>disabled <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"d-flex flex-column justify-content-center align-items-center"</span><span class="token operator">></span> <span class="token operator"><</span>img src<span class="token operator">=</span><span class="token punctuation">{</span>window<span class="token punctuation">.</span>captchaImage<span class="token punctuation">}</span> className<span class="token operator">=</span><span class="token string">"img-fluid mb-4"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>button className<span class="token operator">=</span><span class="token string">"btn btn-primary"</span> onClick<span class="token operator">=</span><span class="token punctuation">{</span>getCaptchaValue<span class="token punctuation">}</span><span class="token operator">></span>Get Value<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token punctuation">{</span>captchaValue <span class="token operator">&&</span> <span class="token operator"><</span>span className<span class="token operator">=</span><span class="token string">"text-danger"</span><span class="token operator">></span>Value<span class="token operator">:</span> <span class="token punctuation">{</span>captchaValue<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> CaptchaSolver<span class="token punctuation">;</span></code></pre></div><p>As you can see we're sending a POST request to an API endpoint which we'll create soon.</p><p>Finally, change the content of <code class="language-text">resources/app.js</code> to render the React component inside the <code class="language-text">#root</code> element:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> ReactDOM <span class="token keyword">from</span> <span class="token string">'react-dom'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Captcha <span class="token keyword">from</span> <span class="token string">'./CaptchaSolver'</span><span class="token punctuation">;</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./bootstrap'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token operator"><</span>Captcha <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'root'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h3 id="adding-the-endpoint">Adding the Endpoint</h3><p>Now, we'll add the endpoint. Here, we'll use 2Captcha's PHP SDK we created earlier.</p><p>First, create a function inside <code class="language-text">CaptchaController</code> that will handle the request:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">solve</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span></code></pre></div><p>Then, inside the function, initialize the SDK with the API Key of your account which you can find in the <a href="https://2captcha.com/setting">account settings</a>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token variable">$solver</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TwoCaptcha</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'API_KEY'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>The SDK offers easy-to-use methods to solve the captcha. As we are just solving a captcha image, we'll use the <a href="https://github.com/2captcha/2captcha-php#normal-captcha">normal method</a>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token variable">$result</span> <span class="token operator">=</span> <span class="token variable">$solver</span><span class="token operator">-></span><span class="token function">normal</span><span class="token punctuation">(</span><span class="token function"><span class="token punctuation">\</span>public_path</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'image'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Finally, we'll return a JSON response with the value received from 2Captcha:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'success'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'value'</span> <span class="token operator">=></span> <span class="token variable">$result</span><span class="token operator">-></span><span class="token property">code</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>We just need to add the new API route. Add the following in <code class="language-text">routes/api.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/solve'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">CaptchaController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'solve'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h3 id="solving-captcha">Solving Captcha</h3><p>Let's test everything out. First, start the server if it's not already started:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan serve</code></pre></div><p>Then, run <code class="language-text">watch</code> command with NPM to compile React's changes:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> run <span class="token function">watch</span></code></pre></div><p>Go to <code class="language-text">localhost:8000</code> (if that's the port it's running on). You'll see a Captcha image with a button.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-19-at-3.43.37-PM.png" class="kg-image" alt="Solve Captcha and reCAPTCHA Challenges with 2Captcha" loading="lazy" width="510" height="356"/></figure><p>Click on the button. A request will be sent to the endpoint and once the response is received, you'll see that 2Captcha solved the captcha challenge correctly.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-19-at-3.44.15-PM.png" class="kg-image" alt="Solve Captcha and reCAPTCHA Challenges with 2Captcha" loading="lazy" width="490" height="386"/></figure><h2 id="conclusion">Conclusion</h2><p>2Captcha is an easy-to-use solver that solves Recaptcha and captchas of all kinds. Using this captcha solving software, it facilitates surfing websites that requires the user to solve the captcha challenge and prove they're human. It also prevents Bot detection.</p><p>Make sure to <a href="http://2captcha.com/?utm_medium=content&utm_source=pakainfo&utm_campaign=en">sign up with 2Captcha</a> now. You can also check out their <a href="https://2captcha.com/support/faq">FAQ</a> page for more info.</p>]]></content:encoded></item><item><title><![CDATA[8 Technical Writing Tips I Learned From Writing For SitePoint, Draft.dev, and More]]></title><description><![CDATA[After writing for these websites I learned some tips that allowed me to improve my technical writing.]]></description><link>https://blog.shahednasser.com/8-technical-writing-tips-i-learned-from-writing-for-sitepoint-draft-dev-and-more/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ebe</guid><category><![CDATA[Tips]]></category><category><![CDATA[My Experience]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 18 Aug 2021 08:53:27 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/83fef51e7789498cab4732f0bff0d685/corinne-kutz-tMI2_-r5Nfo-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/83fef51e7789498cab4732f0bff0d685/corinne-kutz-tMI2_-r5Nfo-unsplash-2.jpg" alt="8 Technical Writing Tips I Learned From Writing For SitePoint, Draft.dev, and More"/><p>Late 2020, after writing articles sporadically, I finally created this blog. Through this blog, I was able to write many articles and tutorials about <a href="https://blog.shahednasser.com/tag/javascript">Javascript</a>, <a href="https://blog.shahednasser.com/tag/browser-extensions">Browser Extensions</a>, <a href="https://blog.shahednasser.com/tag/magento">Magento 2</a>, and more.</p><p>Then, in May 2021, I branched out and applied to write for different platforms. I landed a couple of gigs and became an author for some notable websites or agencies like <a href="https://www.sitepoint.com">SitePoint</a>, <a href="https://draft.dev">Draft.dev</a>, <a href="https://logrocket.com">LogRocket</a>, <a href="https://contentlab.io">ContentLab</a>, and more. Check the <a href="https://blog.shahednasser.com/my-guest-writings/">My Guest Writings</a> page to see some of them.</p><p>After writing for these websites or some of their clients, I learned so many things regarding different technologies. I also learned some tips that allowed me to improve my technical writing. In this article, I'll share some of them with you, and in the end, I'll add some links in case you want to apply to these platforms, as well.</p><h2 id="start-with-an-outline">Start with an Outline</h2><p>Previously, I would get an idea or a concept I'd think would be good to write about. Then, I'd start writing right away, or if it's a tutorial I'd start coding in parallel. However, when I started writing for SitePoint, I was always asked to provide an outline before I start writing an article. Similarly for Draft.dev whenever I was assigned an article, it always starts with an outline.</p><p>Defining an outline for your article organizes your thoughts and ideas before getting into them. You might have a lot of useful knowledge to share, but it gets lost between the spontaneous sentences here and there. Outlining the topic's headlines first allows you to organize where each thought, idea, or tip should go.</p><p>If you're not sure how you can write an outline, there are <a href="https://www.sitepoint.com/writing-for-money-tips-for-planning-your-next-article-pitch/">some tutorials</a> that can help you get started. However, you can also start with outlining articles in your thoughts if that's easier. Take time to plan how the article's structure will look, and once you think you're confident enough in the planned headings and ideas flow, you can start writing the article.</p><h2 id="simplify-tutorials">Simplify Tutorials</h2><p>When a certain section in your tutorial requires setting up something that isn't actually necessary to the topic of the tutorial, simplify that as best as possible. Here's an example: let's say you're doing a tutorial on something related to Node.js. You might need to store the data somehow, so you end up choosing MySQL as the database. So, you'll have to add setup instructions in your tutorial related to setting up the database, when it's actually not necessary to the tutorial.</p><p>This can cause confusion, especially if the reader doesn't know about MySQL (in the example I'm giving) enough to keep up, or maybe they don't have a MySQL server installed on their machine anyway. Make sure your tutorials are simple and to the point. Even if something seems simple to you, it might be a hurdle to the reader and they end up leaving your tutorial trying to find a simpler one. In the example above, if you need to use something to store the data you can try using something simple like an SQLite database where there won't be any complicated configurations required. Even if the reader doesn't know anything about it, then don't really need to know to keep going with the article.</p><h2 id="stay-consistent">Stay Consistent</h2><p>When writing an article or a tutorial, it's important to stay consistent. This applies to many things. First, don't use different spellings throughout the article. For example, don't use Javascript at one point then use JavaScript at another. Second, make sure your code is consistent. Don't use <code class="language-text">"</code> at some points then use <code class="language-text">'</code> in others, or don't omit <code class="language-text">;</code> in some code blocks and leave it in others. Although these details might not seem like they're a big deal, providing consistency keeps your article organized and uniform.</p><h2 id="dont-assume-the-reader-knows">Don't Assume The Reader Knows</h2><p>A lot of times we use certain words, phrases, abbreviations, or overlook details thinking they're basics and just like we know them, the reader will know them as well. It's important to cater your articles to readers in general. </p><p>When using abbreviations, you should at least use the full word or phrase once with its abbreviation, then you can use the abbreviation after that. For example, if your article mentions Create React App, you might be inclined to just use CRA. Instead, the first time you mention it you should do it as "Create React App (CRA)", then refer to it as CRA in the rest of your article.</p><p>When it comes to tutorials, for example, using methods, try to link to documentation on that method even if your tutorial explains it briefly. This allows the reader to delve more into the details if they need to and see any additional details you might have overshadowed as they don't necessarily fit into the tutorial. You can link to documentation from <a href="https://developer.mozilla.org/en-US/">MDN Web Docs</a> or other websites depending on the programming language you're using.</p><h2 id="always-link-to-sources">Always Link to Sources</h2><p>Similar to the previous section, you should always link to sources when possible. If you mention a survey or study results, browser limitations, quotes from other articles or books, or anything that comes from an original source, link back to it. This builds your article's credibility and maintains trust with the reader. Also, it allows the reader to check it out for themselves and see the details if needed.</p><h2 id="create-a-style-guide">Create a Style Guide</h2><p>When you first start writing articles, you might not care much about following a certain guideline for your articles. However, for the consistency of the blog as a whole and to maintain a certain structure for your articles, it's good to have a style guide. A style guide that an article must follow includes the type of headings it should use, certain words or formatting of the content, and other rules you can add yourself that you find are helpful through your journey in writing. You might be confused on how to start, but the more you write and start understanding the kind of blog you're creating, the clearer it comes.</p><p>Try to start by creating a certain guideline for the content formatting. For example, a new line should be added before every new section or after every headline in the article. Start with simple guidelines and grow the list with time.</p><h2 id="have-an-average-word-count">Have an Average Word Count</h2><p>A good tip I've learned by writing for all these different platforms is to keep an article between 1500~2000 words. You don't have to always keep the article in that range, but it's good to have an average range just to keep yourself in check and know when an article can be shortened or split into parts, or when it should be longer with more details.</p><p>A lot of times I write a long article, then I take a second look at it and realize that I repeated myself a lot of times unnecessarily. After writing an article, if it's too long try to remove any unnecessary details or repeated statements. Make sure the article or tutorial focuses on its main purpose rather than unnecessary details. This helps the reader to get the best out of it when reading it and not get lost in irrelevant details. If it's a tutorial and can be split into parts, do that as it will be easier for the reader.</p><p>On the other hand, if an article is too short take a second look at it. Are there ambiguous details? Is there room for confusion or misunderstandings? If so, take the time to re-iterate or elaborate on what you want to say or teach the reader. A lot of times we think that our point is coming across well, or what we are trying to teach is easily understood, but in reality, the article ends up missing the main point.</p><h2 id="learn-and-write">Learn and Write</h2><p>Before I started writing, I got to a point where I stopped learning new things. I just stuck to what I knew and never evolved. When I started writing, I started expanding my knowledge and learning new things to write about. Especially when I started writing for platforms like SitePoint or Draft.dev. A lot of times I was assigned an article that I had a basic knowledge of, or some I barely knew anything about. However, because I had to write about it for an article, I researched and went deep into the details of the topics. This helped me learn new things and expand my knowledge. I wasn't only writing to help others, I was learning through the process as well.</p><h2 id="bonus-be-confident-in-what-you-know">Bonus: Be Confident In What You Know</h2><p>A lot of people want to write but are scared that their knowledge is nothing compared to others, or that it will not benefit anyone. I felt the same way too when I started this blog. I thought that what I knew everyone knew, and that writing about these topics will not benefit anyone. However, after I started writing about all the different topics I had knowledge of, I received so many messages and emails thanking me for helping them resolve an issue they faced, learn more about a topic, or help them understand some things more. Even if you think your knowledge is limited, that does not mean others can't learn from you. None of us know everything, and someone is bound to learn from what you have to share.</p><p>Additionally, even if no one reads or benefits from your article, you'll benefit yourself. Every single article or tutorial I wrote I learned something new from it. Sometimes it's minor details when I'm trying or searching for something, sometimes it's the entire topic. At the end of the day, there's at least one person learning from your writings, so be confident about it.</p><h2 id="conclusion">Conclusion</h2><p>If you're considering writing for these platforms, don't hesitate or think you can't do it. You can always apply and try, and hopefully, you'll learn through writing for them as well.</p><p>I'll leave the links to apply to write for these websites below. Take the time to go through them if it interests you.</p><ul><li><a href="https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwjh8urvgLHyAhUE1hoKHfByDFEQFnoECAgQAw&url=https%3A%2F%2Fwww.sitepoint.com%2Fwrite-for-us%2F&usg=AOvVaw17PGRzWlDU3-SpPm2yZ1AB">SitePoint</a></li><li><a href="https://draft.dev/write">Draft.dev</a></li><li><a href="https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwiS1oj2gLHyAhWBzoUKHUOkAZEQFnoECAMQAQ&url=https%3A%2F%2Fblog.logrocket.com%2Fbecome-a-logrocket-guest-author%2F&usg=AOvVaw21Npb2S-nFefEDCz-Rcgng">LogRocket</a></li><li><a href="https://contentlab.io/write-for-contentlab/">ContentLab.io</a></li></ul>]]></content:encoded></item><item><title><![CDATA[Should You Create a Jamstack Blog?]]></title><description><![CDATA[We'll go over what Jamstack is, briefly how you can create a blog with Jamstack, and whether you should or shouldn't use Jamstack to create your blog.]]></description><link>https://blog.shahednasser.com/should-you-create-a-jamstack-blog/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ebc</guid><category><![CDATA[Tips]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 16 Aug 2021 07:49:08 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/2978531db5ceaae4d560a204544e1801/alisa-anton-TFB-yM97hGg-unsplash--1-.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/2978531db5ceaae4d560a204544e1801/alisa-anton-TFB-yM97hGg-unsplash--1-.jpg" alt="Should You Create a Jamstack Blog?"/><p>If you're considering starting a blog or renovating an existing one, you'll probably find many frameworks or technologies to build your blog with. The process of choosing the best one can be confusing, especially as you branch out in finding the best choice.</p><p>One way to create your blog is using <a href="https://jamstack.org/">Jamstack</a>. Jamstack uses a set of tools and commands to serve your blog statically. By doing so, you're separating the frontend from the backend, leading to a faster website, better security, and more flexibility.</p><p>We'll go over what Jamstack is, briefly how you can create a blog with Jamstack, and whether you should or shouldn't use Jamstack to create your blog.</p><h2 id="what-is-jamstack">What is Jamstack?</h2><p><a href="https://vimeo.com/163522126">Presented in 2016</a> by Mathias (Matt) Biilmann, CEO of <a href="https://www.netlify.com/">Netlify</a>, Jamstack's main purpose is to provide a website statically, while also allowing the content to be dynamic. This is done using Javascript, APIs, and Markdown.</p><p>Jamstack can be used to build many kinds of websites, including blogs built with <a href="https://www.gatsbyjs.com/">Gatsby</a>, <a href="https://gohugo.io/">Hugo</a>, or other similar frameworks. This works by decoupling the frontend from the backend and using tools in the framework or technologies used in the backend to generate the static site.</p><p>By doing this, your static website will be much faster, as it is separated from the backend's logic. Furthermore, this provides better security for your backend, as it would typically be hosted separately from the frontend. In addition, separating the backend from the frontend makes your stack more flexible. This means that you can optimize your backend, make changes, undergo maintenance, and more without affecting the frontend. This also means you can focus on improving the UI and the design as a whole of the frontend without worrying about the architecture of the backend.</p><h2 id="how-can-you-create-a-jamstack-blog">How Can You Create a Jamstack Blog?</h2><p>We'll go over this briefly, as it depends on the stack you'll use and how you'll link the frontend to it. There are many tutorials for each of the different frameworks that you can use as the backend to your Jamstack Blog and how you can deploy them.</p><p>Let's take <a href="https://ghost.org/">Ghost</a> as an example. You can create a Jamstack blog that is linked to your Ghost backend using Gatsby. There are already a lot of <a href="https://jamstackthemes.dev/cms/ghost/">ready themes</a> that you can use to get started, or you create a theme on your own.</p><p>What you would do is you'll host Ghost, which will be the backend, on one server. Then, you'll create a GitHub repository of the Gatsby project that will get the data from the backend and generate the static site, which will be the frontend. Then, you can deploy this GitHub repository on Netlify. This way, you'll have your Jamstack blog hosted on Netlify, completely separate from the Ghost backend. You can also add an integration for Netlify in Ghost to trigger a build whenever a change happens or a new article is posted.</p><p>This is a general overview of how it works. There are a lot of different frameworks and tools that can be used to create a Jamstack blog.</p><h3 id="recommended-tool">Recommended Tool</h3><p><a href="https://dropinblog.com">DropInBlog</a> is one of those tools that can help you create a fully functioning headless blog using Jamstack methods. It helps to remove the need to use more fragile client-based JavaScript, moreover, remove reliance on heavier code. It’s the best option, especially if you are considering content marketing as it opens up to all SEO options while being extremely easy to navigate and very powerful. Check out this tutorial by DropInBlog on <a href="https://dropinblog.com/blog/blogging-on-the-jamstack-with-netlify-and-eleventy/">how to create a Jamstack blog</a>. Therefore, if you are considering creating a headless blog, Jamstack is the right technology for building a fully-functioning blog using 3rd party integration. You just need a few lines of code in the custom HTML area and you are ready to publish it.</p><h2 id="why-should-you-create-a-blog-using-jamstack">Why Should You Create a Blog Using Jamstack?</h2><h3 id="faster-blog-and-better-seo">Faster Blog and Better SEO</h3><p>Static sites are served to your users faster than websites that use frameworks to generate their pages and content. Users love fast websites, as they can be impatient. If they find a website is faster than another while still providing the content or information they need, they'll visit the faster website. </p><p>Google's ranking system for its search engine relies a lot on the experience you provide your users and your website's performance. As your Jamstack blog will be fast with a good performance, it will get more traffic and rank higher on search engines.</p><h3 id="more-flexibility">More Flexibility</h3><p>By decoupling the backend and the frontend, you have more flexibility in your choice of implementing the frontend as fitting your needs. You don't have to worry about the entire architecture of the CMS framework you are using. If you're interested in customizing your website in great detail, then using Jamstack would be a good choice for you.</p><h3 id="better-security-and-availability">Better Security and Availability</h3><p>With the backend and frontend hosted separately, the backend is kept secure away from the users visiting the blog. There is no direct connection between the blog and the backend and there are no requests performed from the blog to the backend and its APIs. Furthermore, the website is static which means it relies on read-only files. So, both the frontend and the backend are less vulnerable to attacks.</p><p>In addition, due to the separation, your blog will always be available, even if the backend is down. As the blog is already generated ahead of time and is served statically, the backend is never accessed when users are visiting your blog. Any issues in your backend or maintenance will not affect the availability of the blog.</p><h3 id="affordable-hosting">Affordable Hosting</h3><p>You'll actually find that when you create a Jamstack blog you have a better chance at using affordable hosting plans, even free ones. If you're looking for a way to host your blog for free, you'll find that most free hostings are a hassle to use, as there are a lot of limitations, especially as your website grows. However, separating the frontend from the backend, makes things easier.</p><p>For example, Netlify offers a generous <a href="https://www.google.com/search?client=safari&rls=en&q=netlify+free+plan&ie=UTF-8&oe=UTF-8">free plan</a>, so you can run your blog for free for a long time before feeling the need to upgrade. As for the backend, there are a few options like <a href="https://www.heroku.com/">Heroku</a> that offer free hosting. Even if they are limited and the server shuts down, for example, due to the amounts of requests performed exceeding the limit, the frontend will still be up and running. So, your blog technically will not be affected by these limitations.</p><h2 id="why-shouldnt-you-create-a-blog-using-jamstack">Why Shouldn't You Create a Blog Using Jamstack?</h2><h3 id="lack-of-development-knowledge">Lack of Development Knowledge</h3><p>You probably have realized this while reading through this article, but you'll need some intermediate development experience to set up your Jamstack blog. It's not hard to learn, but it is something you'll need to consider before starting.</p><p>If you're not a developer, you can still create a Jamstack blog with some friendly interfaces and one-click deploys like <a href="https://www.netlifycms.org/docs/start-with-a-template/">Netlify CMS</a>. However, that does not completely eliminate the need to do some coding, especially as your blog grows. Adding some features will require you to use code at certain points.</p><h3 id="less-interactive-features">Less Interactive Features</h3><p>Blogs are not just about posting your thoughts and opinions but also about interacting with your readers. One form of interacting with them is through comments. In Jamstack blogs, it's not natively possible to have comments functionality, as the blog does not connect to any database or endpoints and it only reads from static files. However, you can still have comments using services like <a href="https://disqus.com">Disqus</a>. The problem with these services is that either you need a paid plan, or opt for the free plan which will place ads on your blog.</p><h3 id="costly-build-times">Costly Build Times</h3><p>As Jamstack blogs are static pages generated from dynamic content using frameworks and tools, the process of generating them takes time. So, if you want to publish a blog post you'll probably have to wait maybe 10 minutes for the build to be done and your website to be deployed with the new blog post. This can be annoying when you want to make edits, as you'll have to wait that same amount of time again even if the change is small. However, this does not affect your website's availability, as it will still be up and running for visitors during the build.</p><h2 id="conclusion">Conclusion</h2><p>Before making your choice, it's always important to check the pros and cons, and whether the option fits your need regardless of their cons. Jamstack is a great option for developers who want to build their blog on their own terms, while also providing a fast user experience and maintaining their blog's security.</p>]]></content:encoded></item><item><title><![CDATA[Factors Companies Should Consider in Establishing A Successful Channel Partner Strategy]]></title><description><![CDATA[One of the most cost-efficient tactics embraced by companies is forging successful partnerships with resellers — also known as channel partners.]]></description><link>https://blog.shahednasser.com/factors-companies-should-consider-in-establishing-a-successful-channel-partner-strategy/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ebd</guid><category><![CDATA[Business]]></category><dc:creator><![CDATA[Chatty Garrate]]></dc:creator><pubDate>Wed, 11 Aug 2021 06:22:38 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/0f6bbe263f6b8290f05c892f65d135c6/mediensturmer-aWf7mjwwJJo-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/0f6bbe263f6b8290f05c892f65d135c6/mediensturmer-aWf7mjwwJJo-unsplash-2.jpg" alt="Factors Companies Should Consider in Establishing A Successful Channel Partner Strategy"/><p>Your company’s sales team only has so much time, and this is one of the biggest challenges in scaling your business. Today, it takes creativity and resourcefulness to reach targets and take market opportunities with fewer resources. </p><p>One of the most cost-efficient tactics embraced by companies today is forging successful partnerships with resellers and distributors — also known as channel partners.</p><h2 id="what-are-channel-partners">What are channel partners?</h2><p>Channel partners are companies whose main objective is to sell or distribute products of a manufacturer. They include resellers, distributors, affiliates, value-added providers, independent retailers — in short, any seller who does not work directly with your company. </p><p>Selling your products through channel partners can help your business in reaching new markets, launching new products, and servicing customers. When done right, channel partnerships can be a game-changer for your business.</p><h2 id="is-channel-sales-right-for-your-business">Is channel sales right for your business?</h2><p>There are a few things to consider before jumping into channel partnerships.</p><ul><li><strong>Company size</strong>. For small companies, hiring and training may not be a cost-efficient route. Channel partners can help you grow your business in the early stages. Once you’ve grown as a company, you can <a href="https://www.rocsstaffing.com/jobs">hire your own representatives</a>; or if your channel partnerships are working great, then press on.</li><li><strong>Product</strong>. If a product is still very new, you may opt to directly sell to your customers in order to have a faster and clearer assessment of what works and what doesn’t.</li><li><strong>Sales Process</strong>. Consider the maturity of your sales process. Before welcoming new partners in selling, you must first establish and define your whole sales process. What are your most important buyer triggers? How long do deals usually take to close?</li><li><strong>Revenue Needs</strong>. If your company needs to generate revenue as soon as possible, then channel partners may not be your go-to strategy. Channel partnerships can take time before they are up and running.</li><li><strong>Location</strong>. If your company embraces the <a href="https://coderslink.com/company/blog/how-to-enhance-your-companys-productivity-using-follow-the-sun-model/">follow-the-sun workflow</a>, meaning your offices are spread out in different locations and time zones, it would make more sense to also use channel partners than multiple sales teams.</li></ul><h2 id="factors-to-consider-in-establishing-a-successful-channel-partner-strategy">Factors to Consider in Establishing a Successful Channel Partner Strategy</h2><p>Channel partners help make your products become more accessible to buyers. However, you might think that utilizing as many channel partners as possible can only be good for your business. It is actually best to make use of only a few, and be strategic about it. In establishing a successful channel partner strategy and choosing the right channel partners, there are a few factors to consider.</p><h3 id="market-focus">Market Focus</h3><p>Your channel partner’s market must be aligned with yours. Take due diligence in finding out their specific target market, their current marketing strategies, and their networking practices. Does your product meet the demands of their current customer base? And does their customer base fit your business in terms of geography, size, and application?</p><h3 id="practice">Practice</h3><p>It is also important to thoroughly research your prospective partner in order to ensure that there is no conflict of interest. From the get-go, make sure that they are not working with any of your key competitors. It is also wise to find out from the start whether your partnership could potentially reduce your selling territory.</p><h3 id="process-and-mentality">Process and Mentality</h3><p>You must identify the commitment level you would want from a channel partner, and also gauge the commitment the potential partner can give. How willing are they to dedicate staff to your business? How do they generate leads? What follow-up process do they have? Are they ready to invest in and undergo training?</p><h3 id="expertise">Expertise</h3><p>Determine what level of technical expertise and types of skills you would require. From there, you would know what to look for. A successful channel partnership means good training plans, sufficient experience in presentations and demonstrations, intact customer service mindset, and technical knowledge. So, look for these aspects for starters.</p><h3 id="stability">Stability</h3><p>Take into account the prospective partner’s business model, too. Is it stable? Consider their size, management competency, growth, and profitability. Their current financial position is a good gauge of whether they are suitable for a long-term partnership. Request for information on gross margin and profit, cash flow, and balance sheet. Information whether they are a public or a private company is important, too.</p><h2 id="final-thoughts">Final Thoughts</h2><p>Partnerships are necessary in gaining more traction as a business and taking as many market opportunities as possible. When done strategically, they can help your business grow and remain competitive. That is why it is important to be strategic in implementing a channel partner strategy and choosing the companies to work with.</p>]]></content:encoded></item><item><title><![CDATA[Register a Keyword in Chrome's Omnibox in Your Extension]]></title><description><![CDATA[In this tutorial, we'll go over how to register a keyword with Chrome's address bar or Omnibox in your extension to handle the user's input.]]></description><link>https://blog.shahednasser.com/register-a-keyword-in-chrome-omnibox-in-your-extension/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ebb</guid><category><![CDATA[Browser Extensions]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 09 Aug 2021 06:43:53 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/89f51a737e7d3c44ffdd7183076e42a1/Register-a-Keyword-in-Chrome-s-Omnibox-2.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/89f51a737e7d3c44ffdd7183076e42a1/Register-a-Keyword-in-Chrome-s-Omnibox-2.png" alt="Register a Keyword in Chrome's Omnibox in Your Extension"/><p>Using Chrome's API, you can do a lot of things in your extension. One of them is registering a keyword in Chrome's address bar, also knows as the <a href="https://developer.chrome.com/docs/extensions/reference/omnibox/#type-DescriptionStyleType">Omnibox</a>, to handle the user's input when the user uses the keyword.</p><p>In this tutorial, we'll go over how to register a keyword with Chrome's address bar or Omnibox in your extension to handle the user's input. The extension we're creating will register the keyword <code class="language-text">color</code>, then when the user uses this keyword in the Omnibox, they can enter a hex color of 6 characters. Once the user enters the hex, the extension will use <a href="http://www.colourlovers.com">COLOURlovers' API</a> to get information about the color and give the user the RGB equivalent of the color.</p><p>It should be noted that this tutorial will create a manifest V2 extension instead of V3. This is due to <a href="https://github.com/GoogleChrome/chrome-extensions-samples/issues/541">an error that occurs with the Omnibox API in manifest V3</a> at the time of writing this article.</p><p>You can find the full code of the extension in this article in <a href="https://github.com/shahednasser/chrome-omnibox-tutorial">this GitHub repository</a>.</p><h2 id="create-the-extension">Create the Extension</h2><p>We'll first create the extension. First, create the directory that will hold the extension. Then, inside the directory, create <code class="language-text">manifest.json</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"hex-to-rgb"</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Convert Hexadecimal colors to RGB right from Chrome's Omnibox"</span><span class="token punctuation">,</span> <span class="token property">"version"</span><span class="token operator">:</span> <span class="token string">"0.0.1"</span><span class="token punctuation">,</span> <span class="token property">"manifest_version"</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token property">"icons"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"16"</span><span class="token operator">:</span> <span class="token string">"images/icon16.png"</span><span class="token punctuation">,</span> <span class="token property">"32"</span><span class="token operator">:</span> <span class="token string">"images/icon32.png"</span><span class="token punctuation">,</span> <span class="token property">"48"</span><span class="token operator">:</span> <span class="token string">"images/icon48.png"</span><span class="token punctuation">,</span> <span class="token property">"128"</span><span class="token operator">:</span> <span class="token string">"images/icon128.png"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>Note that for the icons I'm using an <a href="https://iconscout.com/icons/color">icon</a> by <a href="https://iconscout.com/contributors/thalita-torres">Thalita Torres</a> on <a href="https://iconscout.com">Iconscout</a>. Make sure to download it either from the website or from the GitHub repository and place them just like detailed in the <code class="language-text">manifest.json</code>.</p><p>Next, open Chrome and go to <code class="language-text">chrome://extensions</code>. Then, enable <em>Developer Mode </em>from the top right if it's not enabled. After that, click on <em>Load Unpacked </em>and choose the directory that you just created for the extension. You should see the extension after that in the list of extensions.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-2.18.29-PM.png" class="kg-image" alt="Register a Keyword in Chrome's Omnibox in Your Extension" loading="lazy" width="838" height="464"/></figure><h2 id="register-omnibox-keyword">Register Omnibox Keyword</h2><p>To register a keyword in your extension, you'll need to add a new key <code class="language-text">omnibox</code> in your <code class="language-text">manifest.json</code>. The value of <code class="language-text">omnibox</code> is an object with the key <code class="language-text">keyword</code>. In our extension, we'll use the keyword <code class="language-text">color</code>. Add the following in your <code class="language-text">manifest.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"omnibox"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"keyword"</span><span class="token operator">:</span> <span class="token string">"color"</span> <span class="token punctuation">}</span></code></pre></div><p>Next, we'll need to add a background script that will listen to when the user enters the keyword and then handle the user's input. Add the following in your <code class="language-text">manifest.json</code> to add a background script:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"persistent"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"background.js"</span><span class="token punctuation">]</span> <span class="token punctuation">}</span></code></pre></div><p>For now, create an empty file <code class="language-text">background.js</code> in the root of the directory.</p><p>Then, go to <code class="language-text">chrome://extensions</code> again and click on the refresh button for your extension. You should see a new background page registered.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-2.35.21-PM.png" class="kg-image" alt="Register a Keyword in Chrome's Omnibox in Your Extension" loading="lazy" width="848" height="458"/></figure><p>Let's test out the keyword we just added. Open a new tab, then enter in the address bar (the Omnibox) <code class="language-text">color</code>. You should see a suggestion for <code class="language-text">hex-to-rgb</code> which is the extension we just created.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-2.35.48-PM.png" class="kg-image" alt="Register a Keyword in Chrome's Omnibox in Your Extension" loading="lazy" width="1818" height="220"/></figure><p>If you press TAB, you'll see that the extension's name is now added on the left in the Omnibox with the extension's icon. This means that now the extension will start receiving the input being entered. As we still haven't added listeners to handle the user's input, nothing will happen at the moment if you enter anything.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-2.35.55-PM.png" class="kg-image" alt="Register a Keyword in Chrome's Omnibox in Your Extension" loading="lazy" width="1822" height="222"/></figure><h2 id="add-a-default-suggestion">Add a Default Suggestion</h2><p>When using the Omnibox API, you can specify a default suggestion that will appear regardless of what the user enters. To do that, you can use the method <code class="language-text">chrome.omnibox.setDefaultSuggestion</code>. This method accepts an object with one property <code class="language-text">description</code>.</p><p>The description property accepts XML styling. This means you can use XML tags to apply minimal styling to the suggestion you're showing to the user. These tags are:</p><ol><li><code class="language-text"><url></code>: shows the text inside it styled as a link.</li><li><code class="language-text"><match></code>: shows the text inside it highlighted.</li><li><code class="language-text"><dim></code>: shows the text inside it dimmed.</li></ol><p>It should be noted that you can also nest the XML tags. For example, you can make a URL also highlighted.</p><p>At the beginning of our background script, we'll add a default suggestion that will let the user know what they need to enter to get a result. Add the following at the beginning of <code class="language-text">background.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>omnibox<span class="token punctuation">.</span><span class="token function">setDefaultSuggestion</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'Enter a hex code of 6 characters to convert to RGB (for example, <match>ffffff</match>)'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Notice that in the <code class="language-text">description</code>, we've used the XML tag <code class="language-text"><match>ffffff</match></code>. This means that the suggestion <code class="language-text">ffffff</code> will be highlighted.</p><p>Let's test it. First, refresh the extension from <code class="language-text">chrome://extensions</code> like we did before. Then, type <code class="language-text">color</code> in a new tab and hit <code class="language-text">TAB</code>. Try entering a character and you'll see the suggestion we just defined in <code class="language-text">background.js</code>. Note that the default suggestion does not appear until at least one character is entered.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-2.46.53-PM.png" class="kg-image" alt="Register a Keyword in Chrome's Omnibox in Your Extension" loading="lazy" width="1812" height="140"/></figure><h2 id="handle-input">Handle Input</h2><p>In this section, we'll handle the input the user enters after entering the keyword. To do that, we'll add an event listener to the event <code class="language-text">chrome.omnibox.onInputChanged</code>. The listener will receive 2 parameters, <code class="language-text">text</code> which is the text the user entered, and <code class="language-text">suggest</code> which is a callback function we should use to send our suggestions that we want to show the user back to Chrome. This event is triggered every time the user enters a character.</p><p>Add the following to <code class="language-text">background.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>omnibox<span class="token punctuation">.</span>onInputChanged<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">text<span class="token punctuation">,</span> suggest</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//check that the length of the text is 6 characters</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>text<span class="token punctuation">.</span>length <span class="token operator">!==</span> <span class="token number">6</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">suggest</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//TODO send the text to the API</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>In our listener, for now, we're just checking if the text's length is not 6, then we're calling the <code class="language-text">suggest</code> callback passing it an empty array.</p><p>Next, we'll send a request to the COLOURlovers API and retrieve the color's information. But before we do that, we need to add the API's URL in the permissions array in <code class="language-text">manifest.json</code> so that requests to the API will be allowed. Add the following to <code class="language-text">manifest.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"permissions"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"http://www.colourlovers.com/*"</span> <span class="token punctuation">]</span></code></pre></div><p>Back to our background script, we'll send a request to the endpoint <a href="http://www.colourlovers.com/api/color/">http://www.colourlovers.com/api/color/</a> using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a>. This endpoint accepts the color as a parameter, then returns an array. The array is either empty if the color is not found (for example, if it's an invalid color) or an array that will hold an object with details about the color. For example, try opening the URL <a href="http://www.colourlovers.com/api/color/ffffff?format=json">http://www.colourlovers.com/api/color/ffffff?format=json</a> in your browser and see how the response will look like.</p><p>Add the following to your background script inside the listener:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token comment">//send text to API</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'http://www.colourlovers.com/api/color/'</span> <span class="token operator">+</span> text <span class="token operator">+</span> <span class="token string">'?format=json'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>data<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//no color was found</span> <span class="token function">suggest</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment">//TODO send suggestion when color exists</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>In case no color was found, we're sending back an empty array to the <code class="language-text">suggest</code> callback. We'll need to handle the case that color was found next and how the suggestion should be sent.</p><p>The suggestion object has 3 properties:</p><ol><li><code class="language-text">content</code>: Holds the text that will be placed inside the Omnibox when the user points at the suggestion.</li><li><code class="language-text">deletable</code>: Whether the user can delete the suggestion from the suggestions history. This property is optional.</li><li><code class="language-text">description</code>: similar to the description property we used in <code class="language-text">setDefaultSuggestion</code>, this will be the text that the user will see in the list of suggestions. It can be styled using the XML tags just as we mentioned in the previous section.</li></ol><p>When a color is received, we'll set the <code class="language-text">content</code> inside the Omnibox to be the RGB value and the URL to the color in case the user wants to see additional information. We'll set the <code class="language-text">description</code> to the color's name, the hex code, and the URL to see more information.</p><p>Add the following code in place of the <code class="language-text">TODO</code> we added in the previous code block:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">suggest</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>rgb<span class="token punctuation">.</span>red<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>rgb<span class="token punctuation">.</span>green<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>rgb<span class="token punctuation">.</span>blue<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> url: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token literal-property property">deletable</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Color name: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>title<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, hex: <match></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>hex<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"></match>, more information: <url></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"></url> </span><span class="token template-punctuation string">`</span></span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre></div><p>Our code to convert the hex to RGB is done. Again, refresh the extension from <code class="language-text">chrome://extensions</code>, open a new tab, type <code class="language-text">color</code> in the Omnibox, and hit TAB. Then, enter a hex color. For example, enter <code class="language-text">f5f5f5</code>. You should see a new suggestion below. Try pointing at the suggestion using the keyboard up and down arrows, and you'll see that the content of the Omnibox has changed to the text we set in <code class="language-text">content</code>.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-3.42.17-PM.png" class="kg-image" alt="Register a Keyword in Chrome's Omnibox in Your Extension" loading="lazy" width="1820" height="214"/></figure><h2 id="handle-choosing-suggestion">Handle Choosing Suggestion</h2><p>The last event we need to handle is when the user selects the suggestion either by clicking on it or hitting enter. This event is <code class="language-text">chrome.omnibox.onInputEntered</code>. The listener to this event receives two parameters: the <code class="language-text">text</code> which is the text inside the Omnibox, and <code class="language-text">OnInputEnteredDisposition</code>, which suggests if the new URL should be opened (if that's the action to be performed by the extension) in the <code class="language-text">currentTab</code>, <code class="language-text">newForegroundTab</code> or <code class="language-text">newBackgroundTab</code>.</p><p>What we'll do is extract the URL from the <code class="language-text">text</code>, then if <code class="language-text">OnInputEnteredDisposition</code> is <code class="language-text">currentTab</code>, we'll replace the URL of the current tab with the URL extracted. Else, we'll open a new tab with the URL.</p><p>In <code class="language-text">background.js</code> add the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>omnibox<span class="token punctuation">.</span>onInputEntered<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">text<span class="token punctuation">,</span> OnInputEnteredDisposition</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> prefixIndex <span class="token operator">=</span> text<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token string">'url: '</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>prefixIndex <span class="token operator">!==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> url <span class="token operator">=</span> text<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span>prefixIndex <span class="token operator">+</span> <span class="token string">'url: '</span><span class="token punctuation">.</span>length<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>OnInputEnteredDisposition <span class="token operator">===</span> <span class="token string">'currentTab'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> chrome<span class="token punctuation">.</span>tabs<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span>url<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> chrome<span class="token punctuation">.</span>tabs<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">{</span>url<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>As explained earlier, we're extracting the <code class="language-text">URL</code> from <code class="language-text">text</code> based on the format we wrote in <code class="language-text">content</code>. Then, we're opening the URL based on the value of <code class="language-text">OnInputEnteredDisposition</code>.</p><p>Let's test it out. Again, refresh the extension from <code class="language-text">chrome://extensions</code>, open a new tab, type <code class="language-text">color</code> in the Omnibox, and hit TAB. Then, enter a hex color. For example, enter <code class="language-text">f5f5f5</code>. Click on the suggestion shown for the color, or point at it with the up and down arrows on your keyboard and hit enter. You'll be taken to the page in COLOURlovers with the information about the color.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-3.49.37-PM.png" class="kg-image" alt="Register a Keyword in Chrome's Omnibox in Your Extension" loading="lazy" width="2880" height="1464"/></figure><h2 id="conclusion">Conclusion</h2><p>Using Chrome's Omnibox API, you can add functionalities to your extension to make it easier for your user to find something or perform certain tasks. Make sure to check out the full <a href="https://developer.chrome.com/docs/extensions/reference/omnibox/#type-DescriptionStyleType">API reference</a> to know more about what you can do with this API.</p>]]></content:encoded></item><item><title><![CDATA[Use Mingo to Easily Manage Your MongoDB Databases]]></title><description><![CDATA[Mingo is a nice, refreshing MongoDB GUI that aims to simplify managing your MongoDB databases and collections.]]></description><link>https://blog.shahednasser.com/use-mingo-to-easily-manage-your-mongodb-databases/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eba</guid><category><![CDATA[Reviews]]></category><category><![CDATA[MongoDB]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 05 Aug 2021 09:58:31 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/0ac80e4df430adcf0810124aeda2e26c/Screen-Shot-2021-08-04-at-1.49.48-PM.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/0ac80e4df430adcf0810124aeda2e26c/Screen-Shot-2021-08-04-at-1.49.48-PM.png" alt="Use Mingo to Easily Manage Your MongoDB Databases"/><p>When it comes to managing your <a href="https://www.mongodb.com">MongoDB</a> databases and collections, there are a few options that provide an easy-to-use GUI. <a href="https://mingo.io/?fpr=shahed">Mingo</a> is one of the best choices.</p><p>If you're not familiar with Mingo, it's a free MongoDB admin that provides a very simple GUI to allow you to manage your MongoDB databases hassle-free. We'll go over how you can easily download and set up Mingo, what are some of its features, and the difference between its Free and Pro plans.</p><h2 id="quick-setup">Quick Setup</h2><p>Using Mingo is very easy. First, you need to go to their website to <a href="https://mingo.io/?fpr=shahed">download Mingo</a>. Once you download and install it on your system, open Mingo. You'll be asked to enter a Mongo URL to create a connection. </p><p>To best test out Mingo, I'll be using a project I've already had set up for the tutorial <a href="https://blog.shahednasser.com/how-to-integrate-mongo-realm-with-react-part-1">How to Integrate MongoDB Realm with React</a>. As a short description of what the database used in the tutorial is, it's called <code class="language-text">sample_restaurants</code> that has 2 collections, <code class="language-text">restaurants</code> and <code class="language-text">neighborhoods</code>. The project revolved around adding reviews for each of the restaurants.</p><p>So, I got my connection string from the MongoDB cluster I had created for the tutorial. If your MongoDB database is local, you can use the local connection string.</p><p>Once the connection is established, that's all that's required. You'll be able to check and navigate your database, collections, documents, and more.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-12.18.03-PM.png" class="kg-image" alt="Use Mingo to Easily Manage Your MongoDB Databases" loading="lazy" width="2880" height="1800"/></figure><h2 id="straightforward-navigation">Straightforward Navigation</h2><p>As I was using Mingo, I was impressed by its easy and intuitive navigation. Everything felt easily accessible. The sidebar is simple and to the point, allowing you to choose quickly which database or collection you want to explore. It also provides easy access to the tools that allow you to create a new connection or add a database to your current connection.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-12.22.30-PM.png" class="kg-image" alt="Use Mingo to Easily Manage Your MongoDB Databases" loading="lazy" width="358" height="746"/></figure><p>When choosing a collection, you'll be able to right away see the documents, perform updates and queries, see the schema and indices details, export or import data, and more. The fact that Mingo scopes these actions based on the collection selected allows you to focus your attention on the collection and perform all the actions you need directly on it.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-10.56.17-AM.png" class="kg-image" alt="Use Mingo to Easily Manage Your MongoDB Databases" loading="lazy" width="2510" height="1492"/></figure><p>Furthermore, Mingo's main view consists of tabs. This means that you can open different collections each in different tabs, or use different tools all in parallel, each not interfering or affecting each other.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-12.26.56-PM.png" class="kg-image" alt="Use Mingo to Easily Manage Your MongoDB Databases" loading="lazy" width="2520" height="68"/></figure><p>In addition to that, when clicking on the "plus" icon to create a new tab, you'll see a search bar that will allow you to easily access whatever part of the data in the current connection. You can enter a database's name, a collection's name, or a document's <code class="language-text">_id</code>, and you'll be able to access it right away.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-10.52.28-AM.png" class="kg-image" alt="Use Mingo to Easily Manage Your MongoDB Databases" loading="lazy" width="2018" height="946"/></figure><h2 id="simple-documents-viewer">Simple Documents Viewer</h2><p>When it comes to viewing documents, even when the collection had a lot of documents (in my case it was over 25k documents), it still did not feel cluttered. The design was very sleek and it stacked the documents comfortably that I was able to see everything at a first glance.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-12.37.26-PM.png" class="kg-image" alt="Use Mingo to Easily Manage Your MongoDB Databases" loading="lazy" width="2514" height="1314"/></figure><p>When choosing a document to get an up-close view of all its fields and values, it's all detailed appropriately for nice viewing. You can easily view and navigate the document and its nested data like arrays and objects.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-11.00.58-AM.png" class="kg-image" alt="Use Mingo to Easily Manage Your MongoDB Databases" loading="lazy" width="2510" height="816"/></figure><p>Editing is as simple as double-clicking any field. You'll be able to enter the new value right from the viewer, and you can even change the type of the field.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-12.39.24-PM.png" class="kg-image" alt="Use Mingo to Easily Manage Your MongoDB Databases" loading="lazy" width="2520" height="504"/></figure><h2 id="prevention-of-accidental-changes">Prevention of Accidental Changes</h2><p>By default when you first add a connection, all databases will be locked. This means that no changes are allowed, you can only view the documents. So, when you want to make any updates, you'll have to confirm you want to unlock the database before making any changes. This prevents any accidental changes to any of the data. You can either unlock the database completely or just for 10 minutes.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-12.43.07-PM.png" class="kg-image" alt="Use Mingo to Easily Manage Your MongoDB Databases" loading="lazy" width="1624" height="606"/></figure><h2 id="variety-of-workspaces">Variety of Workspaces</h2><p>Mingo allows you to create 2 types of workspaces: Project or Connection. The connection workspace is similar to any GUI you've used before. It will be scoped to just a connection URL and it will include all the databases in that connection. The project scope allows you to include and view multiple connections in one place. This is helpful when you have a database locally and for production. You can view the databases and synchronize them as well.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-11.03.13-AM.png" class="kg-image" alt="Use Mingo to Easily Manage Your MongoDB Databases" loading="lazy" width="1738" height="812"/></figure><h2 id="cool-dark-mode">Cool Dark Mode</h2><p>As an avid dark mode lover, seeing this feature made me happy. Mingo allows you to choose from the settings between light and dark mode. Its dark mode has a sleek design that feels cool and easy to the eye.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-11.10.06-AM.png" class="kg-image" alt="Use Mingo to Easily Manage Your MongoDB Databases" loading="lazy" width="2504" height="1140"/></figure><h2 id="useful-tools">Useful Tools</h2><h3 id="compare-sync">Compare & Sync</h3><p>Mingo provides useful tools other than the usual tools you would see in other MongoDB clients. One of them is <em>Compare & Sync</em>. This tool allows you to choose 2 databases and compare the collections and documents inside these 2 databases.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-11.10.39-AM.png" class="kg-image" alt="Use Mingo to Easily Manage Your MongoDB Databases" loading="lazy" width="1954" height="676"/></figure><p>Once the comparison is done, if any differences are found between the 2 databases, you can choose to synchronize the databases to make them similar.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-11.18.35-AM.png" class="kg-image" alt="Use Mingo to Easily Manage Your MongoDB Databases" loading="lazy" width="2508" height="306"/></figure><h3 id="nodejs-shell">Node.js Shell</h3><p>Another cool feature that Mingo provides is that it allows you to perform queries or changes on the database using a Node.js Shell. This means you can use the Javascript code you would use on your backend here. This can be useful when testing your code or to easily copy and paste certain queries you want to perform.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-08-04-at-1.40.41-PM.png" class="kg-image" alt="Use Mingo to Easily Manage Your MongoDB Databases" loading="lazy" width="2516" height="1094"/></figure><h2 id="free-vs-pro">Free vs Pro</h2><p>Mingo is available for download for free. The free plan allows you to use ALL of the features mentioned above, which makes it a pretty generous free plan. However, with the free plan, you can only have 1 connection and 1 project. If you need more connections and more projects, consider <a href="https://mingo.io/?fpr=shahed">buying the Pro plan</a>. It's a very cheap plan that fully unlocks Mingo, allowing you to have an unlimited number of connections and projects.</p><h2 id="conclusion">Conclusion</h2><p>Mingo is a nice, refreshing MongoDB GUI that aims at simplifying managing your MongoDB databases and collections. Don't hesitate to <a href="https://mingo.io/?fpr=shahed">try Mingo</a> today and unlock all these awesome features!</p>]]></content:encoded></item><item><title><![CDATA[What is Proof by Contradiction]]></title><description><![CDATA[Proving using contradiction stays the more famous and familiar way mathematicians like to use.]]></description><link>https://blog.shahednasser.com/what-is-proof-by-contradiction/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eb9</guid><category><![CDATA[Mathematics]]></category><dc:creator><![CDATA[Mohammad Nasser]]></dc:creator><pubDate>Tue, 03 Aug 2021 06:36:39 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/fa3f06117ec25cf0260fbb794aeb5110/pawel-czerwinski-lw5KEl7JoB0-unsplash--1-.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/fa3f06117ec25cf0260fbb794aeb5110/pawel-czerwinski-lw5KEl7JoB0-unsplash--1-.jpg" alt="What is Proof by Contradiction"/><p>In mathematics, one of the most famous ways of proving theorems and propositions is to prove by contradiction. Actually, this is a logical way of thinking based on "the law on non-contradiction (LNC)" as first formalized as a metaphysical principle by Aristotle.</p><p>This way of proving says that a statement P and its negation (non)P can not happen at the same time. For example, day and night can not happen at the same time; similarly, left and right, up and down, and full and empty.</p><p>So, to prove a theorem or a proposition, you may either prove that its statement is right, or the negation of its statement is wrong.</p><p>Using the contradiction in proving a theorem or a proposition in mathematics starts usually by assuming that the statement of this theorem or proposition is wrong. Then, the researcher should find a mistake as a result of his assumption. Thus, the statement must not be wrong by contradiction, and so it is true.</p><p>For example, we will prove, using contradiction, the following statement P: "If <code class="language-text">x^2</code> is even, then <code class="language-text">x</code> is even". Suppose to get a contradiction that <code class="language-text">x</code> is odd, that is <code class="language-text">x=n+1</code>, where <code class="language-text">n</code> is an even number. So, <code class="language-text">x^2=(n+1)^2=n^2+2n+1</code>. Then <code class="language-text">x^2-(n)^2-2n=1</code> an odd number, hence the number <code class="language-text">y= x^2-(n)^2-2n</code> is an odd number. On the other hand, <code class="language-text">x^2</code> is even, <code class="language-text">(n)^2</code> is even since <code class="language-text">n</code> is even and <code class="language-text">2n</code> is even, which implies that <code class="language-text">y</code> is even. So, <code class="language-text">y</code> is odd and even at the same time, which is a contradiction. Therefore, the statement P is true.</p><h3 id="conclusion">Conclusion</h3><p>Although there are a lot of ways for proving theorems and propositions in mathematics, proving using contradiction stays the more famous and familiar way mathematicians like to use.</p>]]></content:encoded></item><item><title><![CDATA[17 React Libraries I've Used in 2021 (So Far)]]></title><description><![CDATA[In this article, I'll go over 17 React libraries that I've used in my projects and I found very helpful.]]></description><link>https://blog.shahednasser.com/17-react-libraries-ive-used-in-2021/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eb8</guid><category><![CDATA[React]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Tips]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Fri, 30 Jul 2021 09:13:41 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/34d8962344282ea14267132f8ba9ed31/janko-ferlic-sfL_QOnmy00-unsplash--1-.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/34d8962344282ea14267132f8ba9ed31/janko-ferlic-sfL_QOnmy00-unsplash--1-.jpg" alt="17 React Libraries I've Used in 2021 (So Far)"/><p>In 2021, so far, I've worked on multiple React projects of different concepts. Some were small websites, some were on a bigger scale. During my work on these projects, I've run into certain use cases or situations where I needed to find React libraries to help or simplify the work.</p><p>In this article, I'll go over 17 React libraries that I've used in my projects and I found very helpful. Note that this list does not include any of the libraries you would use in every React project - for example, <a href="https://reactrouter.com/">React Router</a> or <a href="https://www.npmjs.com/package/react-helmet">React Helmet</a>. This list will include libraries that would be used when necessary in a project.</p><h3 id="react-autosuggest">React Autosuggest</h3><p>I've used <a href="https://github.com/moroshko/react-autosuggest">React Autosuggest</a> in a couple of my projects in 2021. React Autosuggest simplifies creating a typeahead input that suggests some values for the user but allows to also use values out of these suggestions. It provides easy-to-use props that allow you to manage how the component in the library fetches the data, displays the data, gets the value from the user's input or selection from suggested values, and more.</p><h3 id="react-toastify">React-Toastify</h3><p><a href="https://github.com/fkhadra/react-toastify">React-Toastify</a> is a library that allows you to give user feedback using awesome toast-like notifications. For developers, the best part about this library is probably how easy it is to set it up and use, while also providing good-looking toast notifications. I've used it in most, if not all, of my projects in 2021. It's a useful library that can make giving feedback or showing notifications less of a hassle in your project.</p><h3 id="react-timer-hook">react-timer-hook</h3><p><a href="https://github.com/amrlabib/react-timer-hook">react-timer-hook</a> provides easy-to-use hooks to handle timers, stopwatches, and time states in your project. This one I used for a very specific use case, where I needed to time how long it took a user to finish a certain task. It might not be a library that you would use in every project, but for its use case, it's definitely helpful.</p><h3 id="use-dark-mode-hook">use-dark-mode-hook</h3><p><a href="https://www.npmjs.com/package/use-dark-mode-hook">use-dark-mode-hook</a> is actually a library that I created myself. It provides a hook to manage the dark mode's state in your project, and a component that allows toggling dark mode. You can use one without the other as necessary. The reason I decided to create this library is that I previously found libraries that do one or the other - that is a library that either provides the toggler component or the hook. So, I wanted to create a library that combines both solutions. I've used it in some of my projects including <a href="https://sbuttons.netlify.app/">sButtons</a>, which is an open-source project I manage.</p><h3 id="react-bootstrap">React-Bootstrap</h3><p>As the name suggests, <a href="https://react-bootstrap.github.io/">React-Bootstrap</a> is a library that has built all <a href="https://getbootstrap.com/">Bootstrap</a> components from scratch to be compatible with React. Bootstrap is a famous CSS library that provides components or styles components that you would use frequently in your own project. Using the library as is with React can be a hassle, as a lot of its components are based on nested HTML elements that have certain classes to provide the styling. However, using React-Bootstrap, these components are easily used as ready-made React components in your project.</p><h3 id="material-tailwind">Material Tailwind</h3><p><a href="https://material-tailwind.com/">Material Tailwind</a> provides React components that are frequently used in almost every project styled using <a href="https://tailwindcss.com/">Tailwind CSS</a>. This library is perfect for your React projects that use Tailwind CSS. It provides a lot of components like Modals, Pagination, Menus, and more, all styled neatly.</p><p><em>Suggested Read: <a href="https://blog.shahednasser.com/useful-tailwind-css-libraries-and-plugins/">Useful Tailwind CSS Libraries and Plugins</a>.</em></p><h3 id="formik">Formik</h3><p><a href="https://formik.org/">Formik</a> is a library that makes building forms in React "without the tears". Forms in React can be a hassle, especially the bigger they get. You have to manage the state of each of the controlled components, handle their validation, show their errors, handle form submissions, and so on. Formik allows you to do all that easily using its Formik component. All you need to do is pass the Formik component what fields are expected to be filled, and it will manage their values, handle changes in the value, and more. Formik also is compatible with <a href="https://github.com/jquense/yup">Yup</a>, making validation even easier by creating validation schemas and passing them to the Formik component.</p><h3 id="heroicons">Heroicons</h3><p><a href="https://heroicons.com/">Heroicons</a> is an icon library made by the makers of Tailwind CSS. You can download the icons from the website as SVG or get the SVG code to be used in JSX, but you can also use their library which provides the icons as components for React and Vue.js. There are a lot of icon libraries out there, but I liked using Heroicons a lot due to the simple design of the icons, the variety of choosing between solid and outline style for each icon, and its easy usage in my React project. It should be noted that even though this library was created by the makers of Tailwind CSS, you can use it in any project even if it does not use or rely on Tailwind CSS.</p><h3 id="react-data-table-component">React Data Table Component</h3><p><a href="https://github.com/jbetancur/react-data-table-component">React Data Table Component</a> is a library that allows you to create data tables with sorting, pagination, and more easily. When working on a project that required creating tables with a lot of data, using pagination, easy cell rendering customization, and more, this library was a big help. It provides a DataTable component that accepts props for the columns and data you want to display, as well as facilitates loading the data from the server with pagination, sorting, and more.</p><h3 id="react-dropzone">react-dropzone</h3><p><a href="https://react-dropzone.js.org/">react-dropzone</a> is a library that provides a simple hook (or alternatively component) to create a dropzone for uploading files. You can specify the file type or size, allow multiple uploads, add preview for the files, and more. This library was very easy to use and its variety of props and event handlers for different use cases allowed to not only use it well as is but also customize it for specific use cases.</p><h3 id="react-spinners">React Spinners</h3><p><a href="https://www.davidhu.io/react-spinners/">React Spinners</a> contains a collection of loading components that you can use in your project. Its variety of loading styles and choices, and its ability to customize these components, make it a good choice to add loading to your React project.</p><h3 id="react-transition-group">React Transition Group</h3><p><a href="https://reactcommunity.org/react-transition-group/">React Transition Group</a> allows you to perform animations on one or more components as they enter and exit. This can be done by using wrapper components like the CSSTransition component, providing it with "enter" and "exit" class names, and adding inside it the elements that you want to have these animations. It makes handling these transition stages like an element entering or exiting easy to implement.</p><h3 id="react-progress-bar">React Progress Bar</h3><p><a href="https://github.com/react-component/progress">React Progress Bar</a> is a library that provides progress bar components to indicate to the user the current progress in percentage. For example, the user's progress of finishing a quiz is based on the number of questions they finished. It's very easy to use and customize as well.</p><h3 id="react-beforeunload">react-beforeunload</h3><p><a href="https://github.com/jacobbuck/react-beforeunload">react-beforeunload</a> is a library that provides a hook and a component to allow handling the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event">beforeunload</a> event. This event occurs on the <code class="language-text">window</code> when the user is about to leave the page. This event is useful to handle when you want to warn the user before leaving that, for example, their changes will not be saved if they leave before saving. So, inside the event handler, you can do a certain check to decide whether the user should see a warning before leaving the page, and if they decide they don't want to leave the page unloads should be canceled and the user will not leave in that case.</p><p>Using this library you can handle this event easily using either the <code class="language-text">useBeforeUnload</code> hook or the <code class="language-text">BeforeUnload</code> component.</p><h3 id="react-simple-pull-to-refresh">react-simple-pull-to-refresh</h3><p><a href="https://github.com/thmsgbrt/react-simple-pull-to-refresh">react-simple-pull-to-refresh</a> provides a wrapper component that, when the user pulls the page down, allows you to handle refreshing the components in that wrapper. This was useful when implementing a Progressive Web App (PWA) to simulate the same "Pull to Refresh" behavior you would get using a mobile app.</p><h3 id="prism-react-renderer">prism-react-renderer</h3><p><a href="https://github.com/FormidableLabs/prism-react-renderer">prism-react-renderer</a> provides a very easy way to use <a href="https://prismjs.com/">Prism.js</a> in React. If you're not familiar with Prism.js, it's a Javascript library that provides beautiful styling and themes for code presentation on your web page. As integrating it with React can be a lot of work, this library allows easy integration, as well as provides a lot of options to customize it.</p><h3 id="react-copy-to-clipboard">react-copy-to-clipboard</h3><p><a href="https://github.com/nkbt/react-copy-to-clipboard">react-copy-to-clipboard</a> is a library that provides a component to allow users to copy something by clicking on it or on a button. The component is easy to use and simplifies implementing the functionality. The component will act as a wrapper to the component that the user needs to click to copy, and you can specify the text that should be copied, as well as handle the <code class="language-text">onCopy</code> event.</p><h2 id="conclusion">Conclusion</h2><p>These are some of the React libraries that facilitated adding or handling certain functionalities in my projects in 2021. If you want to share some of your libraries, make sure to share this article on Twitter, list some of the libraries you've used in 2021, and of course, mention me <a href="https://twitter.com/shahednasserr">@shahednasserr</a> in it!</p>]]></content:encoded></item><item><title><![CDATA[5 Simple Tips For Marketing Automation]]></title><description><![CDATA[We're taking a look at five simple, no-brainer tips for marketing automation.]]></description><link>https://blog.shahednasser.com/5-simple-tips-for-marketing-automation/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eb6</guid><category><![CDATA[Business]]></category><dc:creator><![CDATA[Andres Hammond]]></dc:creator><pubDate>Tue, 27 Jul 2021 16:37:40 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/c36d4d75421600a2ee459495bf8ba1f1/campaign-creators-RSc6D7bO0fA-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/c36d4d75421600a2ee459495bf8ba1f1/campaign-creators-RSc6D7bO0fA-unsplash-2.jpg" alt="5 Simple Tips For Marketing Automation"/><p>Whether you're a business owner, manager, or marketing expert, there's no doubt that you already have a lot of work on your plate!</p><p>From studying your target audience, your competitors and then planning and implementing your well-balanced marketing strategy, it's easy to find yourself overwhelmed and frustrated by how little time there is in a day.</p><p>Fortunately, there are many ways that today's modern, tech-savvy business owners and managers are automating their marketing efforts, in turn, giving them more time to focus on the things that matter most to their businesses.</p><p>Below, we're taking a look at five simple, no-brainer tips for marketing automation.</p><h2 id="know-your-goals">Know Your Goals</h2><p>As with any marketing or advertising, your campaign won't succeed unless you have a few clearly defined goals or objectives in mind.</p><p>Similarly, when it comes to marketing automation, you'll need to know what you want to achieve with your marketing efforts before choosing software tools or services to use.</p><p>For instance, your marketing automation goals might be:</p><ul><li>To improve customer service and support</li><li>To automate your lead generation process</li><li>Or even to make your team seem bigger than it is</li></ul><p>The key here is to ensure that you're creating <a href="https://www.mindtools.com/pages/article/smart-goals.htm">SMART goals</a>, which are specific, measurable, attainable, realistic, and timely.</p><h2 id="choose-reputable-marketing-software">Choose Reputable Marketing Software</h2><p>Today, there are countless <a href="https://businesscards.co/">marketing tools and resources</a> available online.</p><p>However, that doesn't mean that all marketing automation software applications or services are created equal.</p><p>In fact, for every sound, highly reputed marketing automation tool on the market, there are a handful of similar software tools that offer incredible results, but that won't likely deliver on their promise.</p><p>Therefore, make sure to do some research. Learn about the best and most popular marketing automation tools on the market.</p><p>And, only ever choose to pay for an automation software that's well-known, reputable, and sure to deliver the results that you're looking for.</p><h2 id="automation-shouldnt-replace-content-production">Automation Shouldn't Replace Content Production</h2><p>It's also important to realize that marketing automation practices, such as the use of chatbots, aren't designed to replace your business's content production process entirely.</p><p>Instead, marketing automation tools should be used as a way to improve, simplify, and compliment that high-quality content you've always been creating.</p><p>After all, although marketing automation tools have come a long way in recent years, they're simply not capable of creating your blog posts, social media posts, or emails for you.</p><h2 id="segmenting-your-audience">Segmenting Your Audience</h2><p>The most effective marketing automation and lead management tools rely on <a href="https://www.thecompassforsbc.org/how-to-guides/how-do-audience-segmentation">proper audience segmentation</a>.</p><p>In other words, segmentation is critical because it will allow you to personalize your automation software and communications, which will help you make automated processes that seem considerably more human, more friendly, and less robotic.</p><p>When it comes to effectively engaging your target audience, segmentation not only improves the way you communicate with your leads but also makes things more straightforward for your sales team.</p><h2 id="review-tweak-and-improve-your-processes">Review, Tweak, And Improve Your Processes</h2><p>Even though you're now using chatbots or other types of marketing automation software, you'll still need to monitor, track, and review your marketing efforts at regular intervals.</p><p>Over time, your marketing campaign goals and objectives are sure to change, which means that the automated processes you create today might not be relevant tomorrow.</p><p>So make sure to regularly update your processes and ensure that they're still as effective as they were when you first implemented them.</p><p>Business owners can use tools like Google Analytics to track and monitor their marketing effectiveness, allowing them to make better, more informed decisions about their automation in the future.</p><h2 id="conclusion">Conclusion</h2><p>Although automation tools and software are still a long way away from completely replacing the need for a human touch, no doubt using such tools can make your marketing efforts much more straightforward.</p><p>Just be sure to know your goals, choose high-quality automation software, and regularly review and revise your automated processes from time to time.</p>]]></content:encoded></item><item><title><![CDATA[Mathematics and Faith]]></title><description><![CDATA[Faith depends on logic somehow. The Human mind could believe in a religion logically, and logic is a domain of mathematics.]]></description><link>https://blog.shahednasser.com/mathematics-and-faith/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eb7</guid><category><![CDATA[Mathematics]]></category><dc:creator><![CDATA[Mohammad Nasser]]></dc:creator><pubDate>Tue, 27 Jul 2021 16:37:31 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/79718a9f39a2189ef04fb52249379f22/antoine-dautry-_zsL306fDck-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/79718a9f39a2189ef04fb52249379f22/antoine-dautry-_zsL306fDck-unsplash-2.jpg" alt="Mathematics and Faith"/><p>Faith depends on logic somehow. The Human mind could believe in a religion logically, and logic is a domain of mathematics.</p><p>There are a lot of proofs for the existence and uniqueness of “GOD” in mathematics. “Kurt Godel” (1906-1978) proved with mathematical logical steps that GOD exists and unique!</p><p>His work is a new way of thinking around ontological arguments defined by Anslem and Decart.</p><p>This argument has been formalized and automated on a computer with higher-orderautomated theorem provers in 2014 in the published research <a href="https://www.researchgate.net/profile/Bruno-Woltzenlogel-Paleo/publication/265050231_Automating_Godel%27s_Ontological_Proof_of_God%27s_Existence_with_Higher-order_Automated_Theorem_Provers/links/584f85f308ae4bc8993987bd/Automating-Goedels-Ontological-Proof-of-Gods-Existence-with-Higher-order-Automated-Theorem-Provers.pdf?origin=publication_detail">Automating Gödel's Ontological Proof of God's Existence with Higher-order Automated Theorem Provers</a>. The computer proved necessarily, there exists God!</p><p>In the image below, we can see the mathematical logical proof of the existence and uniqueness of God done by Kurt Godel.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/WhatsApp-Image-2021-07-25-at-12.17.00-PM.jpg" class="kg-image" alt="Mathematics and Faith" loading="lazy" width="684" height="748"/></figure><h3 id="conclusion">Conclusion</h3><p>I think that there are a lot of combinations between mathematical logic and faith. It is a new open domain we could work in.</p>]]></content:encoded></item><item><title><![CDATA[Adding an Image Uploader in an Admin Form in Magento 2]]></title><description><![CDATA[In this tutorial, we'll see how to add an ImageUploader component to a form on the admin side that allows us to upload images.]]></description><link>https://blog.shahednasser.com/adding-an-image-uploader-in-an-admin-form-in-magento-2/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eb5</guid><category><![CDATA[Magento]]></category><category><![CDATA[PHP]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 26 Jul 2021 15:25:44 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/9157dd8c027b9e029d85863e32ac6e36/glenn-carstens-peters-npxXWgQ33ZQ-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/9157dd8c027b9e029d85863e32ac6e36/glenn-carstens-peters-npxXWgQ33ZQ-unsplash-2.jpg" alt="Adding an Image Uploader in an Admin Form in Magento 2"/><p>Admin forms in Magento 2 are built with UI Components. There are different types of UI Components that allow us to create many types of fields in forms. One of them is the <a href="https://devdocs.magento.com/guides/v2.4/ui_comp_guide/components/image-uploader/?itm_source=devdocs&itm_medium=quick_search&itm_campaign=federated_search&itm_term=imageuploade">ImageUploader</a> component.</p><p>In this tutorial, we'll see how to add an ImageUploader component to a form on the admin side that allows us to upload images.</p><h2 id="prerequisites">Prerequisites </h2><p>In this section we'll go over the basics of creating a module, adding a menu item on the admin side, and creating a grid that shows the images we uploaded before we start working on our form. If you already know how to do all of that or you just need to see how to create a form with the ImageUploader component, you can skip this section.</p><h3 id="create-the-module">Create the Module</h3><p>We'll quickly go over how to create a module in Magento 2. Create in <code class="language-text">app/code</code> the directories <code class="language-text">VENDOR/MODULE</code> where <code class="language-text">VENDOR</code> is your name or your company's name and <code class="language-text">MODULE</code> is the name of the module. We'll name this module <code class="language-text">ImageUploader</code>.</p><p>Make sure to replace all instances of <code class="language-text">VENDOR</code> with the vendor name you choose, as it will be in every code snippet throughout the tutorial.</p><p>Then, inside <code class="language-text">ImageUploader</code> create <code class="language-text">registration.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Component<span class="token punctuation">\</span>ComponentRegistrar</span><span class="token punctuation">;</span> <span class="token class-name static-context">ComponentRegistrar</span><span class="token operator">::</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token class-name static-context">ComponentRegistrar</span><span class="token operator">::</span><span class="token constant">MODULE</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'VENDOR_ImageUploader'</span><span class="token punctuation">,</span> <span class="token constant">__DIR__</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span></code></pre></div><p>Create a directory called <code class="language-text">etc</code> and inside it create <code class="language-text">module.xml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token prolog"><?xml version="1.0"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>config</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:framework:Module/etc/module.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>module</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR_ImageUploader<span class="token punctuation">"</span></span> <span class="token attr-name">setup_version</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0.0.1<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>config</span><span class="token punctuation">></span></span> </code></pre></div><p>These are the only files required to create a module. Next, we'll need to create the scripts to create a table in the database to store the path of the images we'll upload. Create a directory called <code class="language-text">Setup</code> inside <code class="language-text">ImageUploader</code>, then create the file <code class="language-text">InstallSchema.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Setup</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>DB<span class="token punctuation">\</span>Ddl<span class="token punctuation">\</span>Table</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Setup<span class="token punctuation">\</span>InstallSchemaInterface</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Setup<span class="token punctuation">\</span>SchemaSetupInterface</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Setup<span class="token punctuation">\</span>ModuleContextInterface</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">InstallSchema</span> <span class="token keyword">implements</span> <span class="token class-name">InstallSchemaInterface</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">install</span><span class="token punctuation">(</span><span class="token class-name type-declaration">SchemaSetupInterface</span> <span class="token variable">$setup</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">ModuleContextInterface</span> <span class="token variable">$context</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$setup</span><span class="token operator">-></span><span class="token function">startSetup</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$imagesTableName</span> <span class="token operator">=</span> <span class="token variable">$setup</span><span class="token operator">-></span><span class="token function">getTable</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'VENDOR_images'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$setup</span><span class="token operator">-></span><span class="token function">getConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">isTableExists</span><span class="token punctuation">(</span><span class="token variable">$imagesTableName</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$imagesTable</span> <span class="token operator">=</span> <span class="token variable">$setup</span><span class="token operator">-></span><span class="token function">getConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">newTable</span><span class="token punctuation">(</span><span class="token variable">$imagesTableName</span><span class="token punctuation">)</span> <span class="token operator">-></span><span class="token function">addColumn</span><span class="token punctuation">(</span> <span class="token string single-quoted-string">'image_id'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Table</span><span class="token operator">::</span><span class="token constant">TYPE_INTEGER</span><span class="token punctuation">,</span> <span class="token constant">null</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token class-name static-context">Table</span><span class="token operator">::</span><span class="token constant">OPTION_IDENTITY</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span> <span class="token class-name static-context">Table</span><span class="token operator">::</span><span class="token constant">OPTION_PRIMARY</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span> <span class="token class-name static-context">Table</span><span class="token operator">::</span><span class="token constant">OPTION_UNSIGNED</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span> <span class="token class-name static-context">Table</span><span class="token operator">::</span><span class="token constant">OPTION_NULLABLE</span> <span class="token operator">=></span> <span class="token constant boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'Image Id'</span> <span class="token punctuation">)</span> <span class="token operator">-></span><span class="token function">addColumn</span><span class="token punctuation">(</span> <span class="token string single-quoted-string">'path'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Table</span><span class="token operator">::</span><span class="token constant">TYPE_TEXT</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token class-name static-context">Table</span><span class="token operator">::</span><span class="token constant">OPTION_NULLABLE</span> <span class="token operator">=></span> <span class="token constant boolean">false</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'Image Path'</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$setup</span><span class="token operator">-></span><span class="token function">getConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">createTable</span><span class="token punctuation">(</span><span class="token variable">$imagesTable</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token variable">$setup</span><span class="token operator">-></span><span class="token function">endSetup</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></span></code></pre></div><p>Make sure to replace <code class="language-text">VENDOR</code> in the table name with the name of your vendor.</p><p>Now, we'll create the necessary models for our table. First, create the directories <code class="language-text">Api/Data</code> under <code class="language-text">ImageUploader</code>, and inside <code class="language-text">Data</code> create the file <code class="language-text">ImageInterface.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Api<span class="token punctuation">\</span>Data</span><span class="token punctuation">;</span> <span class="token keyword">interface</span> <span class="token class-name-definition class-name">ImageInterface</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token constant">ID</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'image_id'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token constant">PATH</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'path'</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">getPath</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">setPath</span> <span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></span></code></pre></div><p>Then, create the directory <code class="language-text">Model</code> under <code class="language-text">ImageUploader</code> and inside it create <code class="language-text">Image.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Model</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>DataObject<span class="token punctuation">\</span>IdentityInterface</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>AbstractModel</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">VENDORE<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Api<span class="token punctuation">\</span>Data<span class="token punctuation">\</span>ImageInterface</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">VENDORE<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>ResourceModel<span class="token punctuation">\</span>Image</span> <span class="token keyword">as</span> ResourceModelImage<span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">Image</span> <span class="token keyword">extends</span> <span class="token class-name">AbstractModel</span> <span class="token keyword">implements</span> <span class="token class-name">ImageInterface</span><span class="token punctuation">,</span> IdentityInterface <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token constant">CACHE_TAG</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'VENDOR_images'</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">getIdentities</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span> <span class="token keyword static-context">self</span><span class="token operator">::</span><span class="token constant">CACHE_TAG</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'_'</span> <span class="token operator">.</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">protected</span> <span class="token keyword">function</span> <span class="token function-definition function">_construct</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">_init</span><span class="token punctuation">(</span><span class="token class-name static-context">ResourceModelImage</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">getPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">getData</span><span class="token punctuation">(</span><span class="token keyword static-context">self</span><span class="token operator">::</span><span class="token constant">PATH</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">setPath</span><span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token keyword static-context">self</span><span class="token operator">::</span><span class="token constant">PATH</span><span class="token punctuation">,</span> <span class="token variable">$value</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></span></code></pre></div><p>Make sure to replace all instances of <code class="language-text">VENDOR</code> with your vendor name.</p><p>Under the directory <code class="language-text">Model</code> create the directory <code class="language-text">ResourceModel</code>. Under <code class="language-text">ResourceModel</code> create the file <code class="language-text">Image.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>ResourceModel</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>ResourceModel<span class="token punctuation">\</span>Db<span class="token punctuation">\</span>AbstractDb</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">Image</span> <span class="token keyword">extends</span> <span class="token class-name">AbstractDb</span> <span class="token punctuation">{</span> <span class="token keyword">protected</span> <span class="token keyword">function</span> <span class="token function-definition function">_construct</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">_init</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'VENDOR_images'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'image_id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></span></code></pre></div><p>Again, make sure to replace <code class="language-text">VENDOR</code> with your vendor name.</p><p>Under the <code class="language-text">ResourceModel</code> directory create a directory called <code class="language-text">Image</code>, and under <code class="language-text">Image</code> create <code class="language-text">Collection.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>ResourceModel<span class="token punctuation">\</span>Image</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>ResourceModel<span class="token punctuation">\</span>Db<span class="token punctuation">\</span>Collection<span class="token punctuation">\</span>AbstractCollection</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>Image</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>ResourceModel<span class="token punctuation">\</span>Image</span> <span class="token keyword">as</span> ResourceModelImage<span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">Collection</span> <span class="token keyword">extends</span> <span class="token class-name">AbstractCollection</span> <span class="token punctuation">{</span> <span class="token keyword">protected</span> <span class="token keyword">function</span> <span class="token function-definition function">_construct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">_init</span><span class="token punctuation">(</span><span class="token class-name static-context">Image</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name static-context">ResourceModelImage</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></span></code></pre></div><p>Finally, create the file <code class="language-text">di.xml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token prolog"><?xml version="1.0"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>config</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:framework:ObjectManager/etc/config.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>preference</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR\ImageUploader\Api\Data\ImageInterface<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR\ImageUploader\Api\Data\Image<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>config</span><span class="token punctuation">></span></span></code></pre></div><p>Now, everything is ready for our models. To enable and compile our module, run the following commands in the root of the Magento project:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php">php bin<span class="token operator">/</span>magento setup<span class="token punctuation">:</span>upgrade php bin<span class="token operator">/</span>magento setup<span class="token punctuation">:</span>di<span class="token punctuation">:</span>compile</code></pre></div><p>If no errors occur, our module has been created successfully.</p><h3 id="add-the-routes">Add the Routes</h3><p>To add routes to be able to access our module on the admin side, create under <code class="language-text">etc</code> the directory <code class="language-text">adminhtml</code>, and inside <code class="language-text">adminhtml</code> create <code class="language-text">routes.xml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token prolog"><?xml version="1.0"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>config</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:framework:App/etc/routes.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>router</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>admin<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>route</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>imageuploader<span class="token punctuation">"</span></span> <span class="token attr-name">frontName</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>imageuploader<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>module</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR_ImageUploader<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>route</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>router</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>config</span><span class="token punctuation">></span></span> </code></pre></div><h3 id="add-a-menu-item-on-the-admin-side">Add a Menu Item on The Admin Side</h3><p>In this section, we'll add a menu item to be able to access the page to upload images. First, create under <code class="language-text">etc</code> the file <code class="language-text">acl.xml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token prolog"><?xml version="1.0"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>config</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:framework:Acl/etc/acl.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>acl</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>resources</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>resource</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento_Backend::admin<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>resource</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR_ImageUploader::upload<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Upload Images<span class="token punctuation">"</span></span> <span class="token attr-name">translate</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>title<span class="token punctuation">"</span></span> <span class="token attr-name">sortOrder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>30<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>resource</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>resources</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>acl</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>config</span><span class="token punctuation">></span></span> </code></pre></div><p>Then, inside <code class="language-text">etc/adminhtml</code> create <code class="language-text">menu.xml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token prolog"><?xml version="1.0"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>config</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:module:Magento_Backend:etc/menu.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>menu</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>add</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR_ImageUploader::images_uploader<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Image Uploader<span class="token punctuation">"</span></span> <span class="token attr-name">translate</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>title<span class="token punctuation">"</span></span> <span class="token attr-name">module</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR_ImageUploader<span class="token punctuation">"</span></span> <span class="token attr-name">sortOrder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span> <span class="token attr-name">resource</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR_ImageUploader::upload<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>add</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR_ImageUploader::images<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>All Images<span class="token punctuation">"</span></span> <span class="token attr-name">translate</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>title<span class="token punctuation">"</span></span> <span class="token attr-name">module</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR_ImageUploader<span class="token punctuation">"</span></span> <span class="token attr-name">sortOrder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">parent</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR_ImageUploader::images_uploader<span class="token punctuation">"</span></span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>imageuploader/images<span class="token punctuation">"</span></span> <span class="token attr-name">resource</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR_ImageUploader::upload<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>menu</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>config</span><span class="token punctuation">></span></span> </code></pre></div><p>This will create a menu item called <em>Image Uploader</em> and when clicking on it the submenu will include the item <em>All Images</em>.</p><p>Now, run the following command to compile the changes:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php bin/magento setup:di:compile</code></pre></div><p>Go to the admin side now and login. You'll see in the sidebar a new menu item called <em>Image Uploader.</em></p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-24-at-8.18.02-PM.png" class="kg-image" alt="Adding an Image Uploader in an Admin Form in Magento 2" loading="lazy" width="1034" height="1636"/></figure><h3 id="create-the-image-listing-page">Create the Image Listing Page</h3><p>We'll now create the page <em>All Images </em>lead to, which will be a grid of the images uploaded.</p><p>Create first the directories <code class="language-text">Controller\Adminhtml\Images</code> under <code class="language-text">ImageUploader</code>. Then, create the file <code class="language-text">Index.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Controller<span class="token punctuation">\</span>Adminhtml<span class="token punctuation">\</span>Images</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">Index</span> <span class="token keyword">extends</span> <span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>Magento<span class="token punctuation">\</span>Backend<span class="token punctuation">\</span>App<span class="token punctuation">\</span>Action</span> <span class="token punctuation">{</span> <span class="token comment">/** * * @var \Magento\Framework\View\Result\PageFactory */</span> <span class="token keyword">protected</span> <span class="token variable">$resultPageFactory</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span> <span class="token class-name class-name-fully-qualified type-declaration"><span class="token punctuation">\</span>Magento<span class="token punctuation">\</span>Backend<span class="token punctuation">\</span>App<span class="token punctuation">\</span>Action<span class="token punctuation">\</span>Context</span> <span class="token variable">$context</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified type-declaration"><span class="token punctuation">\</span>Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>View<span class="token punctuation">\</span>Result<span class="token punctuation">\</span>PageFactory</span> <span class="token variable">$resultPageFactory</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword static-context">parent</span><span class="token operator">::</span><span class="token function">__construct</span><span class="token punctuation">(</span><span class="token variable">$context</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">resultPageFactory</span> <span class="token operator">=</span> <span class="token variable">$resultPageFactory</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/** @var \Magento\Backend\Model\View\Result\Page $resultPage */</span> <span class="token variable">$resultPage</span> <span class="token operator">=</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">resultPageFactory</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$resultPage</span><span class="token operator">-></span><span class="token function">setActiveMenu</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'VENDOR_ImageUploader::images_uploader'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$resultPage</span><span class="token operator">-></span><span class="token function">getConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">getTitle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">prepend</span><span class="token punctuation">(</span><span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Images'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token variable">$resultPage</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></span></code></pre></div><p>Then, under <code class="language-text">ImageUploader</code> create the directories <code class="language-text">view/adminhtml/layout</code> and inside <code class="language-text">layout</code> create <code class="language-text">imageuploader_images_index.xml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token prolog"><?xml version="1.0"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>page</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:framework:View/Layout/etc/page_configuration.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>referenceContainer</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>content<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>uiComponent</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>images_list<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>referenceContainer</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>page</span><span class="token punctuation">></span></span></code></pre></div><p>After that, create under <code class="language-text">view/adminhtml</code> the directory <code class="language-text">ui_component</code>, and inside that directory create the file <code class="language-text">images_list.xml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token prolog"><?xml version="1.0"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>listing</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:module:Magento_Ui:etc/ui_configuration.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>argument</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>data<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>array<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>js_config<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>array<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>provider<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>images_list.images_list_data_source<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>argument</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>buttons</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>upload<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>url</span> <span class="token attr-name">path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>*/*/upload<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>class</span><span class="token punctuation">></span></span>primary<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>class</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">translate</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Upload Images<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>buttons</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>spinner</span><span class="token punctuation">></span></span>images_columns<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>spinner</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>deps</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>dep</span><span class="token punctuation">></span></span>images_list.images_list_data_source<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>dep</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>deps</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>dataSource</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>images_list_data_source<span class="token punctuation">"</span></span> <span class="token attr-name">component</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento_Ui/js/grid/provider<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>storageConfig</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>param</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>indexField<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>image_id<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>param</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>storageConfig</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>updateUrl</span> <span class="token attr-name">path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mui/index/render<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>dataProvider</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>images_list_data_source<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>requestFieldName</span><span class="token punctuation">></span></span>id<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>requestFieldName</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>primaryFieldName</span><span class="token punctuation">></span></span>image_id<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>primaryFieldName</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>dataProvider</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>dataSource</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>columns</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>images_columns<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>column</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image_id<span class="token punctuation">"</span></span> <span class="token attr-name">sortOrder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>filter</span><span class="token punctuation">></span></span>text<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>filter</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>dataType</span><span class="token punctuation">></span></span>text<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>dataType</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">translate</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>ID<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>column</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>column</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>path<span class="token punctuation">"</span></span> <span class="token attr-name">component</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento_Ui/js/grid/columns/thumbnail<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR\ImageUploader\Ui\Component\Columns\Thumbnail<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>hasPreview</span><span class="token punctuation">></span></span>0<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>hasPreview</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>addField</span><span class="token punctuation">></span></span>false<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>addField</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">translate</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Thumbnail<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>sortable</span><span class="token punctuation">></span></span>false<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>sortable</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>column</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>columns</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>listing</span><span class="token punctuation">></span></span></code></pre></div><p>This will create a grid listing that will show the uploaded images. It will show 2 columns, the ID and a thumbnail. To show the thumbnail, we need to create the class for the UI Component. Create under <code class="language-text">ImageUploader</code> the directories <code class="language-text">Ui\Component\Columns</code>, and inside <code class="language-text">Columns</code> create the file <code class="language-text">Thumbnail.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Ui<span class="token punctuation">\</span>Component<span class="token punctuation">\</span>Columns</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Backend<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>UrlInterface</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>View<span class="token punctuation">\</span>Element<span class="token punctuation">\</span>UiComponent<span class="token punctuation">\</span>ContextInterface</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>View<span class="token punctuation">\</span>Element<span class="token punctuation">\</span>UiComponentFactory</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Store<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>StoreManagerInterface</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Ui<span class="token punctuation">\</span>Component<span class="token punctuation">\</span>Listing<span class="token punctuation">\</span>Columns<span class="token punctuation">\</span>Column</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">Thumbnail</span> <span class="token keyword">extends</span> <span class="token class-name">Column</span> <span class="token punctuation">{</span> <span class="token comment">/** * * @var StoreManagerInterface */</span> <span class="token keyword">protected</span> <span class="token variable">$storeManagerInterface</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span> <span class="token class-name type-declaration">ContextInterface</span> <span class="token variable">$context</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">UiComponentFactory</span> <span class="token variable">$uiComponentFactory</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">StoreManagerInterface</span> <span class="token variable">$storeManagerInterface</span><span class="token punctuation">,</span> <span class="token keyword type-hint">array</span> <span class="token variable">$components</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword type-hint">array</span> <span class="token variable">$data</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword static-context">parent</span><span class="token operator">::</span><span class="token function">__construct</span><span class="token punctuation">(</span><span class="token variable">$context</span><span class="token punctuation">,</span> <span class="token variable">$uiComponentFactory</span><span class="token punctuation">,</span> <span class="token variable">$components</span><span class="token punctuation">,</span> <span class="token variable">$data</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">storeManagerInterface</span> <span class="token operator">=</span> <span class="token variable">$storeManagerInterface</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">prepareDataSource</span><span class="token punctuation">(</span><span class="token keyword type-hint">array</span> <span class="token variable">$dataSource</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">foreach</span><span class="token punctuation">(</span><span class="token variable">$dataSource</span><span class="token punctuation">[</span><span class="token string double-quoted-string">"data"</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string double-quoted-string">"items"</span><span class="token punctuation">]</span> <span class="token keyword">as</span> <span class="token operator">&</span><span class="token variable">$item</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">isset</span><span class="token punctuation">(</span><span class="token variable">$item</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'path'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$url</span> <span class="token operator">=</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">storeManagerInterface</span><span class="token operator">-></span><span class="token function">getStore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">getBaseUrl</span><span class="token punctuation">(</span><span class="token class-name static-context">UrlInterface</span><span class="token operator">::</span><span class="token constant">URL_TYPE_MEDIA</span><span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token variable">$item</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'path'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token variable">$item</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'path_src'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token variable">$url</span><span class="token punctuation">;</span> <span class="token variable">$item</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'path_alt'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token variable">$item</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'image_id'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token variable">$item</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'path_link'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token variable">$url</span><span class="token punctuation">;</span> <span class="token variable">$item</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'path_orig_src'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token variable">$url</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token variable">$dataSource</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></span></code></pre></div><p>This class will extend <code class="language-text">Magento\Ui\Component\Listing\Columns\Column</code> and override the function <code class="language-text">prepareDataSource</code>. In this function, we're making changes to the <code class="language-text">path</code> column to show a thumbnail. To be able to show a thumbnail using the component <code class="language-text">Magento_Ui/js/grid/columns/thumbnail</code>, we need to add to each row in the table the fields <code class="language-text">FIELD_src</code>, <code class="language-text">FIELD_alt</code>, <code class="language-text">FIELD_link</code> and <code class="language-text">FIELD_orig_src</code>, where <code class="language-text">FIELD</code> is the name of the field of the thumbnail, in this case, it's <code class="language-text">path</code>.</p><p>Finally, add the following to <code class="language-text">etc/di.xml</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>type</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>arguments</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>argument</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>collections<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>array<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>images_list_data_source<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> VENDOR\ImageUploader\Model\ResourceModel\Image\Grid\Collection <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>argument</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>arguments</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>type</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>virtualType</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR\ImageUploader\Model\ResourceModel\Image\Grid\Collection<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>arguments</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>argument</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mainTable<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>VENDOR_images<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>argument</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>argument</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>resourceModel<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>VENDOR\ImageUploader\Model\ResourceModel\Image <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>argument</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>arguments</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>virtualType</span><span class="token punctuation">></span></span></code></pre></div><p>Our image listing page is ready. We need to compile the changes first:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php bin/magento setup:di:compile</code></pre></div><p>Then, log in to the admin side again and click on <em>ImageUploader -> All Images. </em>A page with an empty table will show and a button to upload new images.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-24-at-8.47.27-PM.png" class="kg-image" alt="Adding an Image Uploader in an Admin Form in Magento 2" loading="lazy" width="2880" height="1110"/></figure><p>Now, we're ready to create the form and add the ImageUploader component to it.</p><h2 id="create-ui-form">Create UI Form</h2><p>First, we'll need to create the controller that will handle the request. Create under <code class="language-text">ImageUploader\Controller\Adminhtml\Images</code> the file <code class="language-text">Upload.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Controller<span class="token punctuation">\</span>Adminhtml<span class="token punctuation">\</span>Images</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">Upload</span> <span class="token keyword">extends</span> <span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>Magento<span class="token punctuation">\</span>Backend<span class="token punctuation">\</span>App<span class="token punctuation">\</span>Action</span> <span class="token punctuation">{</span> <span class="token comment">/** * * @var \Magento\Framework\View\Result\PageFactory */</span> <span class="token keyword">protected</span> <span class="token variable">$resultPageFactory</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span> <span class="token class-name class-name-fully-qualified type-declaration"><span class="token punctuation">\</span>Magento<span class="token punctuation">\</span>Backend<span class="token punctuation">\</span>App<span class="token punctuation">\</span>Action<span class="token punctuation">\</span>Context</span> <span class="token variable">$context</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified type-declaration"><span class="token punctuation">\</span>Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>View<span class="token punctuation">\</span>Result<span class="token punctuation">\</span>PageFactory</span> <span class="token variable">$resultPageFactory</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword static-context">parent</span><span class="token operator">::</span><span class="token function">__construct</span><span class="token punctuation">(</span><span class="token variable">$context</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">resultPageFactory</span> <span class="token operator">=</span> <span class="token variable">$resultPageFactory</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/** @var \Magento\Backend\Model\View\Result\Page $resultPage */</span> <span class="token variable">$resultPage</span> <span class="token operator">=</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">resultPageFactory</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$resultPage</span><span class="token operator">-></span><span class="token function">setActiveMenu</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'VENDOR_ImageUploader::images_uploader'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$resultPage</span><span class="token operator">-></span><span class="token function">getConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">getTitle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">prepend</span><span class="token punctuation">(</span><span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Upload Image'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token variable">$resultPage</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></span></code></pre></div><p>Like <code class="language-text">Index.php</code>, this one just shows the page. We'll need to create the layout for this page. Create under <code class="language-text">view/adminhtml/layout</code> the file <code class="language-text">imageuploader_images_upload.xml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token prolog"><?xml version="1.0"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>page</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:framework:View/Layout/etc/page_configuration.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>referenceContainer</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>content<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>uiComponent</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>images_form<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>referenceContainer</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>page</span><span class="token punctuation">></span></span></code></pre></div><p>This is just showing a UI Component called <code class="language-text">images_form</code>, which we'll create next. Create under <code class="language-text">view/adminhtml/ui_component</code> the file <code class="language-text">images_form.xml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token prolog"><?xml version="1.0"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>form</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:module:Magento_Ui:etc/ui_configuration.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>argument</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>data<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>array<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>js_config<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>array<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>provider<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>images_form.images_form_data_source<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>label<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span> <span class="token attr-name">translate</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Upload Images<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>reverseMetadataMerge<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>boolean<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>template<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>templates/form/collapsible<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>config<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>array<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dataScope<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>data<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>namespace<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>images_form<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>argument</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>buttons</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>save<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR\ImageUploader\Block\Adminhtml\Form\UploadButton<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>back<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR\ImageUploader\Block\Adminhtml\Form\BackButton<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>buttons</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>deps</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>dep</span><span class="token punctuation">></span></span>images_form.images_form_data_source<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>dep</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>deps</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>dataSource</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>images_form_data_source<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>argument</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dataProvider<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>configurableObject<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>argument</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>name<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>images_form_data_source<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>argument</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>argument</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>class<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>VENDOR\ImageUploader\Ui\Component\Form\DataProvider<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>argument</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>argument</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>primaryFieldName<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>image_id<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>argument</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>argument</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>requestFieldName<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>id<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>argument</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>argument</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>data<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>array<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>config<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>array<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submit_url<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>url<span class="token punctuation">"</span></span> <span class="token attr-name">path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>*/*/save<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>argument</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>argument</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>argument</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>data<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>array<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>js_config<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>array<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>component<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Ui/js/form/provider<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>argument</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>dataSource</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>fieldset</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">translate</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Upload Images<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>field</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image<span class="token punctuation">"</span></span> <span class="token attr-name">formElement</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>imageUploader<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">translate</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Images<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>componentType</span><span class="token punctuation">></span></span>imageUploader<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>componentType</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>validation</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rule</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>required-entry<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>boolean<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>rule</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>validation</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>formElements</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>imageUploader</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>allowedExtensions</span><span class="token punctuation">></span></span>jpg jpeg png<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>allowedExtensions</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>maxFileSize</span><span class="token punctuation">></span></span>2097152<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>maxFileSize</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>uploaderConfig</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>param</span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>url<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>imageuploader/images/tempUpload<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>param</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>uploaderConfig</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>imageUploader</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>formElements</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>field</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>fieldset</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>form</span><span class="token punctuation">></span></span></code></pre></div><p>This just creates the UI Form component. Before we dive into the components and classes this form needs, let's look at the ImageUploader component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>field</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image<span class="token punctuation">"</span></span> <span class="token attr-name">formElement</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>imageUploader<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">translate</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Images<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>componentType</span><span class="token punctuation">></span></span>imageUploader<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>componentType</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>validation</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rule</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>required-entry<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>boolean<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>rule</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>validation</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>formElements</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>imageUploader</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>allowedExtensions</span><span class="token punctuation">></span></span>jpg jpeg png<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>allowedExtensions</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>maxFileSize</span><span class="token punctuation">></span></span>2097152<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>maxFileSize</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>uploaderConfig</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>param</span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>url<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>imageuploader/images/tempUpload<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>param</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>uploaderConfig</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>settings</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>imageUploader</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>formElements</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>field</span><span class="token punctuation">></span></span></code></pre></div><p>Notice that we've defined this field as an ImageUploader through <code class="language-text"><componentType>imageUploader</componentType></code>. We've also made this field required by adding <code class="language-text"><rule name="required-entry" xsi:type="boolean">true</rule></code> to <code class="language-text"><validation></code>. Then, inside <code class="language-text"><formElements></code>, we're adding a couple of settings for the <code class="language-text"><imageUploader></code>. <code class="language-text">allowedExtensions</code> allows us to specify the extensions allowed, which are in this case <code class="language-text">jpg</code>, <code class="language-text">jpeg</code>, and <code class="language-text">png</code>. <code class="language-text">maxFileSize</code> is the maximum size allowed for the file being uploaded. and finally, the param <code class="language-text">url</code> inside <code class="language-text">uploaderConfig</code> is the <code class="language-text">url</code> to send to the uploaded image for temporary upload. This is used to show a preview of the image being uploaded.</p><p>This form component needs a few PHP Classes to be created to be able to function correctly.</p><p>First, we've added 2 buttons, back and upload:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>save<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR\ImageUploader\Block\Adminhtml\Form\UploadButton<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>back<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>VENDOR\ImageUploader\Block\Adminhtml\Form\BackButton<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span></code></pre></div><p>So, let's create the classes for them. Create first the directories <code class="language-text">Block\Adminhtml\Form</code>. Then, create under <code class="language-text">Form</code> the file <code class="language-text">UploadButton.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Block<span class="token punctuation">\</span>Adminhtml<span class="token punctuation">\</span>Form</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>View<span class="token punctuation">\</span>Element<span class="token punctuation">\</span>UiComponent<span class="token punctuation">\</span>Control<span class="token punctuation">\</span>ButtonProviderInterface</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">UploadButton</span> <span class="token keyword">implements</span> <span class="token class-name">ButtonProviderInterface</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">getButtonData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'label'</span> <span class="token operator">=></span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Upload'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'save primary'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'data_attribute'</span> <span class="token operator">=></span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'mage-init'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'button'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'event'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'save'</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'form-role'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'save'</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'sort_order'</span> <span class="token operator">=></span> <span class="token number">90</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></span></code></pre></div><p>This button just takes the user to the save path. The save path is defined in <code class="language-text">images_form.xml</code> in this line:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submit_url<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>url<span class="token punctuation">"</span></span> <span class="token attr-name">path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>*/*/save<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span></code></pre></div><p>Also, create the file <code class="language-text">BackButton.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Block<span class="token punctuation">\</span>Adminhtml<span class="token punctuation">\</span>Form</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Backend<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>UrlInterface</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>View<span class="token punctuation">\</span>Element<span class="token punctuation">\</span>UiComponent<span class="token punctuation">\</span>Control<span class="token punctuation">\</span>ButtonProviderInterface</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">BackButton</span> <span class="token keyword">implements</span> <span class="token class-name">ButtonProviderInterface</span> <span class="token punctuation">{</span> <span class="token comment">/** @var UrlInterface */</span> <span class="token keyword">protected</span> <span class="token variable">$urlInterface</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span> <span class="token class-name type-declaration">UrlInterface</span> <span class="token variable">$urlInterface</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">urlInterface</span> <span class="token operator">=</span> <span class="token variable">$urlInterface</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">getButtonData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'label'</span> <span class="token operator">=></span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Back'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'on_click'</span> <span class="token operator">=></span> <span class="token function">sprintf</span><span class="token punctuation">(</span><span class="token string double-quoted-string">"location.href = '%s';"</span><span class="token punctuation">,</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">getBackUrl</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'back'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'sort_order'</span> <span class="token operator">=></span> <span class="token number">10</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">getBackUrl</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">urlInterface</span><span class="token operator">-></span><span class="token function">getUrl</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'*/*/'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></span></code></pre></div><p>This button just takes the user back to the index page, which is the page that has the image listing.</p><p>Next, we need to create the following classes that are defined in <code class="language-text">images_form.xml</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>argument</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>class<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>VENDOR\ImageUploader\Ui\Component\Form\DataProvider<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>argument</span><span class="token punctuation">></span></span> </code></pre></div><p>This is the data provider class. Usually, this class is very important when the form has an edit functionality. This is where the data for the record being edited is filled to show in the form fields.</p><p>Create under the directory <code class="language-text">Ui\Component\Form</code> the file <code class="language-text">DataProvider.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Ui<span class="token punctuation">\</span>Component<span class="token punctuation">\</span>Form</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Registry</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">DataProvider</span> <span class="token keyword">extends</span> <span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>Magento<span class="token punctuation">\</span>Ui<span class="token punctuation">\</span>DataProvider<span class="token punctuation">\</span>AbstractDataProvider</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span> <span class="token keyword type-hint">string</span> <span class="token variable">$name</span><span class="token punctuation">,</span> <span class="token keyword type-hint">string</span> <span class="token variable">$primaryFieldName</span><span class="token punctuation">,</span> <span class="token keyword type-hint">string</span> <span class="token variable">$requestFieldName</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Registry</span> <span class="token variable">$registry</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified type-declaration"><span class="token punctuation">\</span>VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>ResourceModel<span class="token punctuation">\</span>Image<span class="token punctuation">\</span>CollectionFactory</span> <span class="token variable">$imageCollectionFactory</span><span class="token punctuation">,</span> <span class="token keyword type-hint">array</span> <span class="token variable">$meta</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword type-hint">array</span> <span class="token variable">$data</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword static-context">parent</span><span class="token operator">::</span><span class="token function">__construct</span><span class="token punctuation">(</span><span class="token variable">$name</span><span class="token punctuation">,</span> <span class="token variable">$primaryFieldName</span><span class="token punctuation">,</span> <span class="token variable">$requestFieldName</span><span class="token punctuation">,</span> <span class="token variable">$meta</span><span class="token punctuation">,</span> <span class="token variable">$data</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">registry</span> <span class="token operator">=</span> <span class="token variable">$registry</span><span class="token punctuation">;</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">collection</span> <span class="token operator">=</span> <span class="token variable">$imageCollectionFactory</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></span></code></pre></div><p>This just returns an empty array since we don't have the edit functionality in our form.</p><p>Finally, we'll create the controller that's supposed to handle the temporary upload of the image to show it in the preview, which is at the URL <code class="language-text">imageuploader/images/tempUpload</code>. So, create under <code class="language-text">Controller\Adminhtml\Images</code> the file <code class="language-text">TempUpload.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Controller<span class="token punctuation">\</span>Adminhtml<span class="token punctuation">\</span>Images</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Backend<span class="token punctuation">\</span>App<span class="token punctuation">\</span>Action<span class="token punctuation">\</span>Context</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Backend<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>UrlInterface</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Controller<span class="token punctuation">\</span>ResultFactory</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Exception<span class="token punctuation">\</span>LocalizedException</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Filesystem</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>MediaStorage<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>File<span class="token punctuation">\</span>UploaderFactory</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Store<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>StoreManagerInterface</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">TempUpload</span> <span class="token keyword">extends</span> <span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>Magento<span class="token punctuation">\</span>Backend<span class="token punctuation">\</span>App<span class="token punctuation">\</span>Action</span> <span class="token punctuation">{</span> <span class="token comment">/** * * @var UploaderFactory */</span> <span class="token keyword">protected</span> <span class="token variable">$uploaderFactory</span><span class="token punctuation">;</span> <span class="token comment">/** * @var Filesystem\Directory\WriteInterface */</span> <span class="token keyword">protected</span> <span class="token variable">$mediaDirectory</span><span class="token punctuation">;</span> <span class="token comment">/** * @var StoreManagerInterface */</span> <span class="token keyword">protected</span> <span class="token variable">$storeManager</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span> <span class="token class-name type-declaration">Context</span> <span class="token variable">$context</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">UploaderFactory</span> <span class="token variable">$uploaderFactory</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Filesystem</span> <span class="token variable">$filesystem</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">StoreManagerInterface</span> <span class="token variable">$storeManager</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword static-context">parent</span><span class="token operator">::</span><span class="token function">__construct</span><span class="token punctuation">(</span><span class="token variable">$context</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">uploaderFactory</span> <span class="token operator">=</span> <span class="token variable">$uploaderFactory</span><span class="token punctuation">;</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">mediaDirectory</span> <span class="token operator">=</span> <span class="token variable">$filesystem</span><span class="token operator">-></span><span class="token function">getDirectoryWrite</span><span class="token punctuation">(</span><span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>App<span class="token punctuation">\</span>Filesystem<span class="token punctuation">\</span>DirectoryList</span><span class="token operator">::</span><span class="token constant">MEDIA</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">storeManager</span> <span class="token operator">=</span> <span class="token variable">$storeManager</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$jsonResult</span> <span class="token operator">=</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">resultFactory</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token class-name static-context">ResultFactory</span><span class="token operator">::</span><span class="token constant">TYPE_JSON</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token variable">$fileUploader</span> <span class="token operator">=</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">uploaderFactory</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'fileId'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'image'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$fileUploader</span><span class="token operator">-></span><span class="token function">setAllowedExtensions</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'jpg'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'jpeg'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'png'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$fileUploader</span><span class="token operator">-></span><span class="token function">setAllowRenameFiles</span><span class="token punctuation">(</span><span class="token constant boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$fileUploader</span><span class="token operator">-></span><span class="token function">setAllowCreateFolders</span><span class="token punctuation">(</span><span class="token constant boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$fileUploader</span><span class="token operator">-></span><span class="token function">setFilesDispersion</span><span class="token punctuation">(</span><span class="token constant boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$fileUploader</span><span class="token operator">-></span><span class="token function">validate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$result</span> <span class="token operator">=</span> <span class="token variable">$fileUploader</span><span class="token operator">-></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">mediaDirectory</span><span class="token operator">-></span><span class="token function">getAbsolutePath</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'tmp/imageUploader/images'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$result</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'url'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">storeManager</span><span class="token operator">-></span><span class="token function">getStore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">getBaseUrl</span><span class="token punctuation">(</span><span class="token class-name static-context">UrlInterface</span><span class="token operator">::</span><span class="token constant">URL_TYPE_MEDIA</span><span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'tmp/imageUploader/images/'</span> <span class="token operator">.</span> <span class="token function">ltrim</span><span class="token punctuation">(</span><span class="token function">str_replace</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'\\'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'/'</span><span class="token punctuation">,</span> <span class="token variable">$result</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'file'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token variable">$jsonResult</span><span class="token operator">-></span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token variable">$result</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">LocalizedException</span> <span class="token variable">$e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$jsonResult</span><span class="token operator">-></span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'errorcode'</span> <span class="token operator">=></span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'error'</span> <span class="token operator">=></span> <span class="token variable">$e</span><span class="token operator">-></span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>Exception</span> <span class="token variable">$e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">error_log</span><span class="token punctuation">(</span><span class="token variable">$e</span><span class="token operator">-></span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">error_log</span><span class="token punctuation">(</span><span class="token variable">$e</span><span class="token operator">-></span><span class="token function">getTraceAsString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token variable">$jsonResult</span><span class="token operator">-></span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'errorcode'</span> <span class="token operator">=></span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'error'</span> <span class="token operator">=></span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'An error occurred, please try again later.'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></span></code></pre></div><p>Let's dissect this to understand it better:</p><ol><li>We're using <code class="language-text">uploaderFactory</code> of type <code class="language-text">Magento\MediaStorage\Model\File\UploaderFactory</code> to first get the uploaded image from the request. We pass it <code class="language-text">fileId</code> with the value <code class="language-text">image</code>, which is the name of the field. If it was named something else like "file" then <code class="language-text">fileId</code> will be <code class="language-text">file</code>.</li><li>We're specifying some rules for validation next. We're setting the allowed extensions with <code class="language-text">setAllowedExtensions</code>. We're also using <code class="language-text">setAllowRenameFiles</code> to allow renaming the file uploaded on upload, <code class="language-text">setAllowCreateFolders</code> to allow creating a folder if it doesn't exist, and <code class="language-text">setFilesDispersion</code> to disable files dispersion.</li><li>Then, we're saving the temporary file to <code class="language-text">tmp/imageUploader/images</code> under the <code class="language-text">media</code> directory in <code class="language-text">pub</code>.</li><li>Finally, we're sending back the URL for the uploaded file.</li></ol><h2 id="upload-and-save-image">Upload and Save Image</h2><p>The last thing we need to implement is the Save controller. This controller will handle the submission of the image to finally upload it and save it in our database. To do that, create under <code class="language-text">Controller\Adminhtml\Images</code> the file <code class="language-text">Save.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Controller<span class="token punctuation">\</span>Adminhtml<span class="token punctuation">\</span>Images</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Backend<span class="token punctuation">\</span>App<span class="token punctuation">\</span>Action<span class="token punctuation">\</span>Context</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Exception<span class="token punctuation">\</span>LocalizedException</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Filesystem</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Validation<span class="token punctuation">\</span>ValidationException</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>MediaStorage<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>File<span class="token punctuation">\</span>UploaderFactory</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">Save</span> <span class="token keyword">extends</span> <span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>Magento<span class="token punctuation">\</span>Backend<span class="token punctuation">\</span>App<span class="token punctuation">\</span>Action</span> <span class="token punctuation">{</span> <span class="token comment">/** * * @var UploaderFactory */</span> <span class="token keyword">protected</span> <span class="token variable">$uploaderFactory</span><span class="token punctuation">;</span> <span class="token comment">/** * @var \VENDOR\ImageUploader\Model\ImageFactory */</span> <span class="token keyword">protected</span> <span class="token variable">$imageFactory</span><span class="token punctuation">;</span> <span class="token comment">/** * @var Filesystem\Directory\WriteInterface */</span> <span class="token keyword">protected</span> <span class="token variable">$mediaDirectory</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span> <span class="token class-name type-declaration">Context</span> <span class="token variable">$context</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">UploaderFactory</span> <span class="token variable">$uploaderFactory</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Filesystem</span> <span class="token variable">$filesystem</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified type-declaration"><span class="token punctuation">\</span>VENDOR<span class="token punctuation">\</span>ImageUploader<span class="token punctuation">\</span>Model<span class="token punctuation">\</span>ImageFactory</span> <span class="token variable">$imageFactory</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword static-context">parent</span><span class="token operator">::</span><span class="token function">__construct</span><span class="token punctuation">(</span><span class="token variable">$context</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">uploaderFactory</span> <span class="token operator">=</span> <span class="token variable">$uploaderFactory</span><span class="token punctuation">;</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">imageFactory</span> <span class="token operator">=</span> <span class="token variable">$imageFactory</span><span class="token punctuation">;</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">mediaDirectory</span> <span class="token operator">=</span> <span class="token variable">$filesystem</span><span class="token operator">-></span><span class="token function">getDirectoryWrite</span><span class="token punctuation">(</span><span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>App<span class="token punctuation">\</span>Filesystem<span class="token punctuation">\</span>DirectoryList</span><span class="token operator">::</span><span class="token constant">MEDIA</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token function">getRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">getMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!==</span> <span class="token string single-quoted-string">'POST'</span> <span class="token operator">||</span> <span class="token operator">!</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">_formKeyValidator</span><span class="token operator">-></span><span class="token function">validate</span><span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token function">getRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">LocalizedException</span><span class="token punctuation">(</span><span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Invalid Request'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//validate image</span> <span class="token variable">$fileUploader</span> <span class="token operator">=</span> <span class="token constant">null</span><span class="token punctuation">;</span> <span class="token variable">$params</span> <span class="token operator">=</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">getRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">getParams</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token variable">$imageId</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'image'</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">isset</span><span class="token punctuation">(</span><span class="token variable">$params</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'image'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token function">count</span><span class="token punctuation">(</span><span class="token variable">$params</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'image'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$imageId</span> <span class="token operator">=</span> <span class="token variable">$params</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'image'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">file_exists</span><span class="token punctuation">(</span><span class="token variable">$imageId</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'tmp_name'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$imageId</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'tmp_name'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token variable">$imageId</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'path'</span><span class="token punctuation">]</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'/'</span> <span class="token operator">.</span> <span class="token variable">$imageId</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'file'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token variable">$fileUploader</span> <span class="token operator">=</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">uploaderFactory</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'fileId'</span> <span class="token operator">=></span> <span class="token variable">$imageId</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$fileUploader</span><span class="token operator">-></span><span class="token function">setAllowedExtensions</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'jpg'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'jpeg'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'png'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$fileUploader</span><span class="token operator">-></span><span class="token function">setAllowRenameFiles</span><span class="token punctuation">(</span><span class="token constant boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$fileUploader</span><span class="token operator">-></span><span class="token function">setAllowCreateFolders</span><span class="token punctuation">(</span><span class="token constant boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$fileUploader</span><span class="token operator">-></span><span class="token function">validateFile</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//upload image</span> <span class="token variable">$info</span> <span class="token operator">=</span> <span class="token variable">$fileUploader</span><span class="token operator">-></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">mediaDirectory</span><span class="token operator">-></span><span class="token function">getAbsolutePath</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'imageUploader/images'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/** @var \VENDOR\ImageUploader\Model\Image */</span> <span class="token variable">$image</span> <span class="token operator">=</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">imageFactory</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$image</span><span class="token operator">-></span><span class="token function">setPath</span><span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">mediaDirectory</span><span class="token operator">-></span><span class="token function">getRelativePath</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'imageUploader/images'</span><span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'/'</span> <span class="token operator">.</span> <span class="token variable">$info</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'file'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$image</span><span class="token operator">-></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">ValidationException</span> <span class="token variable">$e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">LocalizedException</span><span class="token punctuation">(</span><span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Image extension is not supported. Only extensions allowed are jpg, jpeg and png'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>Exception</span> <span class="token variable">$e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//if an except is thrown, no image has been uploaded</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">LocalizedException</span><span class="token punctuation">(</span><span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Image is required'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">messageManager</span><span class="token operator">-></span><span class="token function">addSuccessMessage</span><span class="token punctuation">(</span><span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Image uploaded successfully'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">_redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'*/*/index'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">LocalizedException</span> <span class="token variable">$e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">messageManager</span><span class="token operator">-></span><span class="token function">addErrorMessage</span><span class="token punctuation">(</span><span class="token variable">$e</span><span class="token operator">-></span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">_redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'*/*/upload'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>Exception</span> <span class="token variable">$e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">error_log</span><span class="token punctuation">(</span><span class="token variable">$e</span><span class="token operator">-></span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">error_log</span><span class="token punctuation">(</span><span class="token variable">$e</span><span class="token operator">-></span><span class="token function">getTraceAsString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">messageManager</span><span class="token operator">-></span><span class="token function">addErrorMessage</span><span class="token punctuation">(</span><span class="token function">__</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'An error occurred, please try again later.'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">_redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'*/*/upload'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></span></code></pre></div><p>This one is pretty similar to <code class="language-text">TempUpload</code>. Again, let's dissect it:</p><ol><li>We're validating the request by checking that the method is <code class="language-text">POST</code> and the form key is valid.</li><li>We're getting the params that are passed to the request.</li><li>We're checking if <code class="language-text">$params['image']</code> is an image, then we're setting the <code class="language-text">imageId</code> to the first image. This is because the <code class="language-text">ImageUploader</code> can accept multiple images.</li><li>After that, we're doing the same steps that we did in <code class="language-text">TempUpload</code>. We're setting some options like the allowed extensions.</li><li>We're saving the file in <code class="language-text">imageUploader/images</code> under the <code class="language-text">media</code> directory in <code class="language-text">pub</code>.</li><li>We're creating a new instance of <code class="language-text">Image</code>, which is the model for the table that we created in this module, and we're setting the path to the path of the image uploaded. After that, we're saving the model.</li><li>If no errors occur and everything works correctly, we're sending a success message and redirecting back to the index page that shows the image listing.</li></ol><p>Our form, all its components, and controllers related to it are ready. We just need to compile our code:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php bin/magento setup:di:compile</code></pre></div><p>After that is done, again, log in to the admin side of your store. Click on <em>ImageUploader -> All Images -> Upload Images. </em>You'll see a form with an image uploader. Try uploading an image by clicking on <em>Upload</em> next to the <em>Images </em>field. The image uploader field will upload the image using the route <code class="language-text">imageuploader/images/tempupload</code> which will upload the image to <code class="language-text">pub/media/tmp/imageuploader/images</code>, then returns the URL. Then, the ImageUploader field will show a preview of the file.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-24-at-9.09.27-PM.png" class="kg-image" alt="Adding an Image Uploader in an Admin Form in Magento 2" loading="lazy" width="2676" height="1204"/></figure><p>Click on the orange button <em>Upload </em>at the top right corner. This will send the form data to the endpoint <code class="language-text">imageuploader/images/save</code>. This one will save the image under <code class="language-text">pub/media/imageuploader/images</code>, then save the image with the path in the table we created for the module. If everything is correct, you'll be redirected to the listing page and you'll see the image you just uploaded.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-24-at-9.26.34-PM.png" class="kg-image" alt="Adding an Image Uploader in an Admin Form in Magento 2" loading="lazy" width="2654" height="732"/></figure><h2 id="conclusion">Conclusion</h2><p>This is how an ImageUploader component works! Next, you can try adding delete functionalities. You can also try adding other fields to the form, if necessary. It will work perfectly well.</p>]]></content:encoded></item><item><title><![CDATA[Easily Create Free Videos with FlexClip]]></title><description><![CDATA[FlexClip is a great tool that allows you to great promotional videos, intro videos, and more for free!]]></description><link>https://blog.shahednasser.com/easily-create-free-videos-with-flexclip/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eb4</guid><category><![CDATA[Reviews]]></category><category><![CDATA[Design]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 24 Jul 2021 16:17:12 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/b9041b68d48550e78592f5da1e139edb/FlexClip.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/b9041b68d48550e78592f5da1e139edb/FlexClip.png" alt="Easily Create Free Videos with FlexClip"/><p>If you're looking to create a promotional video for your blog or business, a how-to video, an intro video, or any other type of video, <a href="https://www.flexclip.com">FlexClip</a> is a great tool that has you covered.</p><p><em>You can use FlexClip for free, but you can also get more with its paid plans. Keep reading to get a coupon code at the end of this article!</em></p><p>I've dabbled around with FlexClip and created a nice promo video. Check it out!</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/cIu5G5hBquU?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""/></figure><p>With FlexClip, you can create your video from scratch, or you can choose from a wide range of templates to start creating your video. These templates are organized into categories including business, technology, education, and more!</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-24-at-3.41.13-PM.png" class="kg-image" alt="Easily Create Free Videos with FlexClip" loading="lazy" width="2702" height="1346"/></figure><p>When you choose a template or start from scratch, you can then start customizing your video through its simple to use, yet powerful interface. The customization interface provides a lot of options including adding videos, images, text, graphical elements, music, and more.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-24-at-3.43.36-PM.png" class="kg-image" alt="Easily Create Free Videos with FlexClip" loading="lazy" width="2880" height="1694"/></figure><p>FlexClip has a wide range of stock media like images and videos. When using the free plan, you can only use 1 stock media per project. You can also upload your own videos or images to add to the video.</p><p>In addition to all these options, you can also choose the ratio of the video. FlexClip also helps by showing you what each ratio is best for. For example, the 1:1 ratio is best for social media websites like Instagram, Twitter, and more.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-24-at-4.08.16-PM.png" class="kg-image" alt="Easily Create Free Videos with FlexClip" loading="lazy" width="936" height="868"/></figure><p>You can add transitions between your videos. You can also add motion for graphical elements or text. This all can be done through FlexClip's easy-to-use interface.</p><p>Once you're done making your edits, you can export your video. You'll have to create an account and verify it, then you can export the video for free! When using the free plan, you can only export the video at 480p, and if you've exceeded the stock media limit, you'll need to add an intro video that shows the video was created by FlexClip.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-24-at-4.28.55-PM.png" class="kg-image" alt="Easily Create Free Videos with FlexClip" loading="lazy" width="2406" height="1266"/></figure><p>When the export is done, you can download the video. You can also right away upload your video to DropBox or Youtube!</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-24-at-4.37.51-PM.png" class="kg-image" alt="Easily Create Free Videos with FlexClip" loading="lazy" width="1950" height="1110"/></figure><h3 id="coupon-code">Coupon Code</h3><p>As mentioned, you can create and export videos from FlexClip for free. However, it comes with some limitations. For that reason, I've brought you a coupon code to get 20% off on any plan! Use the code <strong>ShahedNasser20 </strong>at checkout and enjoy 20% off!</p>]]></content:encoded></item><item><title><![CDATA[Beginner’s Guide to Validation in Laravel]]></title><description><![CDATA[In this tutorial, we’ll go over how you can validate a form in Laravel using the available methods and create custom validation rules in Laravel.]]></description><link>https://blog.shahednasser.com/beginners-guide-to-validation-in-laravel/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eb3</guid><category><![CDATA[Laravel]]></category><category><![CDATA[PHP]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 21 Jul 2021 15:16:50 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/0c154b313c816e888744311b85f783e3/markus-spiske-6pflEeSzGUo-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/0c154b313c816e888744311b85f783e3/markus-spiske-6pflEeSzGUo-unsplash-2.jpg" alt="Beginner’s Guide to Validation in Laravel"/><p>One of the most important aspects of any project is validating data that are coming into your system. It’s essential to provide the proper validation rules that will ensure your system will be secure and invulnerable to attacks. </p><p>In this tutorial, we’ll go over how you can validate a form in Laravel using the available methods and create custom validation rules in Laravel.</p><h2 id="prerequisites">Prerequisites</h2><p>We’ll quickly go over how to install and set up a Laravel project. If you already have one ready, you can skip this section.</p><p>First, make sure you have <a href="https://getcomposer.org/download/">Composer</a> installed. Then, install a new Laravel project with the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">composer</span> create-project laravel/laravel validation-tutorial</code></pre></div><p>Then, change the directory to the project created and run the serve</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> validation-tutorial php artisan serve</code></pre></div><p>And with that, the server will start running and you can access it on <code class="language-text">localhost:8000</code> or the port specified when running the <code class="language-text">serve</code> command. </p><p><em>If you get an error about permissions, change the `storage` directory permissions to be readable.</em></p><h2 id="create-a-form">Create a Form</h2><p>Create the file <code class="language-text">resources/views/form.blade.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span><span class="token operator">!</span><span class="token constant">DOCTYPE</span> html<span class="token operator">></span> <span class="token operator"><</span>html lang<span class="token operator">=</span><span class="token string double-quoted-string">"en"</span><span class="token operator">></span> <span class="token operator"><</span>head<span class="token operator">></span> <span class="token operator"><</span>meta charset<span class="token operator">=</span><span class="token string double-quoted-string">"UTF-8"</span><span class="token operator">></span> <span class="token operator"><</span>meta http<span class="token operator">-</span>equiv<span class="token operator">=</span><span class="token string double-quoted-string">"X-UA-Compatible"</span> content<span class="token operator">=</span><span class="token string double-quoted-string">"IE=edge"</span><span class="token operator">></span> <span class="token operator"><</span>meta name<span class="token operator">=</span><span class="token string double-quoted-string">"viewport"</span> content<span class="token operator">=</span><span class="token string double-quoted-string">"width=device-width, initial-scale=1.0"</span><span class="token operator">></span> <span class="token operator"><</span>title<span class="token operator">></span>Register<span class="token operator"><</span><span class="token operator">/</span>title<span class="token operator">></span> <span class="token operator"><</span>link href<span class="token operator">=</span><span class="token string double-quoted-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"</span> rel<span class="token operator">=</span><span class="token string double-quoted-string">"stylesheet"</span> integrity<span class="token operator">=</span><span class="token string double-quoted-string">"sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"</span> crossorigin<span class="token operator">=</span><span class="token string double-quoted-string">"anonymous"</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>head<span class="token operator">></span> <span class="token operator"><</span>body <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"bg-light"</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"container bg-white shadow mx-auto mt-5 rounded"</span><span class="token operator">></span> <span class="token operator"><</span>form method<span class="token operator">=</span><span class="token string double-quoted-string">"POST"</span> action<span class="token operator">=</span><span class="token string double-quoted-string">""</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"py-3 p-5"</span><span class="token operator">></span> @csrf <span class="token operator"><</span>h1 <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"text-center"</span><span class="token operator">></span> Register <span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"name"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-label"</span><span class="token operator">></span>Name<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"text"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"name"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"name"</span> aria<span class="token operator">-</span>describedby<span class="token operator">=</span><span class="token string double-quoted-string">"nameHelp"</span> required<span class="token operator">></span> <span class="token operator"><</span>div id<span class="token operator">=</span><span class="token string double-quoted-string">"nameHelp"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-text"</span><span class="token operator">></span>Please enter both first <span class="token keyword">and</span> last name<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"date_of_birth"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-label"</span><span class="token operator">></span>Date of Birth<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"date"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"date_of_birth"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"date_of_birth"</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-label"</span><span class="token operator">></span>Email address<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> required<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"password"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-label"</span><span class="token operator">></span>Password<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"password"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"password"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"password"</span> required<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"password_confirmation"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-label"</span><span class="token operator">></span>Password Confirmation<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"password"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"password_confirmation"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"password_confirmation"</span> required<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"text-center"</span><span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string double-quoted-string">"submit"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"btn btn-primary"</span><span class="token operator">></span>Submit<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>script src<span class="token operator">=</span><span class="token string double-quoted-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"</span> integrity<span class="token operator">=</span><span class="token string double-quoted-string">"sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"</span> crossorigin<span class="token operator">=</span><span class="token string double-quoted-string">"anonymous"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>body<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>html<span class="token operator">></span> </code></pre></div><p>This will create a page with a form that has 5 input fields: Name, Date of Birth, Email, Password, and Password Confirmation. Note that for easy styling I’ve added the Bootstrap CDN for the CSS and JS files, however, it’s better to <a href="https://getbootstrap.com/docs/5.0/getting-started/download/">download them</a> and use them in your project.</p><p>The current form just currently accepts the input. However, we haven’t added the `action` which will accept the input, and we aren’t showing any error messages or success messages from the server.</p><p>Next, we’ll create a controller that will handle all the requests related to the form. Run the following command to do that:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan make:controller FormController</code></pre></div><p>This will create a new controller in <code class="language-text">app/Http/Controllers/FormController.php</code>. Open it and a new function <code class="language-text">showForm</code> that just returns the view we just created:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">showForm</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'form'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Finally, let’s create the new route in `routes/web.php`:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token comment">//add the following in the beginning</span> <span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>FormController</span><span class="token punctuation">;</span> <span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/register'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">FormController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'showForm'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Let’s see our form now. Start the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan serve</code></pre></div><p>And go to <code class="language-text">localhost:8000/register</code>. You’ll see the form we created.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-02-at-3.40.44-PM.png" class="kg-image" alt="Beginner’s Guide to Validation in Laravel" loading="lazy" width="2844" height="1314"/></figure><h2 id="create-the-form-action-route">Create The Form Action Route</h2><p>We’ll create now the route that will accept the inputs and validate them. In <code class="language-text">app/Http/Controllers/FormController.php</code>, create a new function called <code class="language-text">register</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">register</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span></code></pre></div><p>Inside the function, we’ll start by validating the input. To validate the input, we use the Validation facade. The Validation facade has a static method called `validate`, which takes 2 parameters. The first is the array of data to validate. The second is the array of validation rules to apply to each of the data.</p><p>The array of validation rules consists of key-value pairs, where the key is the name of the field in the input received (for example, `name`), and the value is a string consisting of the validation rules to apply. For example, to ensure that `name` is always present in the parameters, we use the following key-value pair in the array of the second parameter:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php">‘name’ <span class="token operator">=></span> ‘required’<span class="token punctuation">,</span></code></pre></div><p>What if we want to use more than one validation rule? We want to ensure that not only is the name present, but it at least has 1 character in it. To separate validation rules in the value string, the separator “|” is used:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php">‘name’ <span class="token operator">=></span> ‘<span class="token class-name">required</span><span class="token operator">|</span><span class="token class-name">min</span><span class="token punctuation">:</span><span class="token number">1</span>’<span class="token punctuation">,</span></code></pre></div><p>Where <a href="https://laravel.com/docs/8.x/validation#rule-min">min</a> ensures that if the <code class="language-text">name</code> is a string, it at least has 1 character.</p><p>Another way to use multiple validation rules is using an array for the value rather than a string:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php">‘name’ <span class="token operator">=></span> <span class="token punctuation">[</span>‘required’<span class="token punctuation">,</span> ‘name’<span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div><p>Let’s start by first using the <code class="language-text">validate</code> function, passing it the data received from the form using <code class="language-text">$request->all()</code>, then we’ll add the validation rules one by one to the second parameter array:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token comment">//validate request</span> <span class="token class-name static-context">Validator</span><span class="token operator">::</span><span class="token function">validate</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>We’ll first add validation rules for the Name input. The Name input is `required` and should be at least 1 character long:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token string single-quoted-string">'name'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'required|min:1'</span><span class="token punctuation">,</span></code></pre></div><p>Second, the Date of Birth input. This input is optional, but when it’s present in the request’s body, it should be a date. So, to make sure it’s optional we use the validation rule <a href="https://laravel.com/docs/8.x/validation#rule-nullable">nullable</a>, and to make sure it’s a date we use the <a href="https://laravel.com/docs/8.x/validation#rule-date">date</a> validation rule:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token string single-quoted-string">'date_of_birth'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'nullable|date'</span><span class="token punctuation">,</span></code></pre></div><p>Third, the Email input. This input is required and it should be validated to be an email. To ensure that the value is an email, we use the <a href="https://laravel.com/docs/8.x/validation#rule-email">email</a> validation rule:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token string single-quoted-string">'email'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'required|email'</span><span class="token punctuation">,</span></code></pre></div><p>And finally, the Password and Password Confirmation inputs. The password is required and should be 8 characters long. So, we’ll use the <code class="language-text">required</code> and <code class="language-text">min</code> validation rules we used earlier. However, it should also be confirmed in the Password Confirmation input. To ensure that, we use the <a href="https://laravel.com/docs/8.x/validation#rule-confirmed">confirmed</a> validation rule. This validation rule searches for another input with the name <code class="language-text">{input}_confirmation</code> where <code class="language-text">{input}</code> is the input name of the input that has the validation rule <code class="language-text">confirmed</code>. So, in this example, it will look for <code class="language-text">password_confirmation</code>. If the password input’s name was <code class="language-text">new_password</code>, it will look for <code class="language-text">new_password_confirmation</code>. For this reason, when using the <code class="language-text">confirmed</code> validation rule, make sure that the confirmation field has that name format.</p><p>So, the validation for the Password and Password Confirmation inputs is:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token string single-quoted-string">'password'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'required|min:8|confirmed'</span><span class="token punctuation">,</span></code></pre></div><p>Note that since we’re using `confirmed` there’s no need to add any validation rules specific to Password Confirmation input, as the `confirmed` rule will check that the Password Confirmation input is present and has the same value as `password`, and if the Password input is not valid then the Password Confirmation is ultimately not valid as well.</p><p>That’s all the validation rules we need for now. The `validate` method will take the data in the first parameter and apply the validation rules from the second parameter. If there are any validation errors, the `validate` method will redirect back to the form with the errors. So, in our code after executing the `validate` method, we can be sure that everything after that will be executed if and only if the data is valid.</p><p>After the form, you can run any logic you need with it that can only be run if the data is valid. For example, save the user in the database or send an email. Here, we’ll just add a success key in the session and redirect back to the form:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token comment">//all valid</span> <span class="token comment">//return success message</span> <span class="token function">session</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">flash</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'success'</span><span class="token punctuation">,</span> <span class="token constant boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">back</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>We’ll use the `success` key in the session to determine whether to show a success message. Note that the `flash` method ensures that this value appears in the session only in the next request, then the value will be automatically removed from the session.</p><p>In the <code class="language-text">showForm</code> method, change the code to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token variable">$success</span> <span class="token operator">=</span> <span class="token function">session</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'success'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'form'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'success'</span> <span class="token operator">=></span> <span class="token variable">$success</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This takes the success value from the session and passes it as a variable to the form view. Now, add the following nested inside the <code class="language-text">form</code> element under the <code class="language-text">h1</code> element in <code class="language-text">resources/views/form.blade.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php">@<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$success</span><span class="token punctuation">)</span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"alert alert-success"</span><span class="token operator">></span> You have registered successfully<span class="token operator">!</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @<span class="token keyword">endif</span> </code></pre></div><p>This checks if the `success` variable evaluates to <code class="language-text">true</code>, it will show a success message to the user that their registration was successful.</p><p>What about error messages? How do we show them in our form?</p><p>You can check if any element has an error message using Blade’s `@error` directive. If there’s an error on the input, everything inside the directive’s block will show. If not, nothing will.</p><p>For example, to add the class <code class="language-text">is-invalid</code> to the name input if it’s not valid:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"text"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"name"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control @error('name') is-invalid @enderror"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"name"</span> aria<span class="token operator">-</span>describedby<span class="token operator">=</span><span class="token string double-quoted-string">"nameHelp"</span> required<span class="token operator">></span></code></pre></div><p>To show the error message, inside the <code class="language-text">@error</code> directive you can reference a <code class="language-text">$message</code> variable, which will be the error of the input:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php">@<span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'name'</span><span class="token punctuation">)</span> <span class="token operator"><</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"invalid-feedback"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$message</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> @enderror</code></pre></div><p>So, let’s make the changes to all the input fields. We’ll add the class <code class="language-text">is-invalid</code> if the input has errors, and we’ll add the error message below the input field. We’ll make the change to the <code class="language-text">name</code>, <code class="language-text">date_of_birth</code>, <code class="language-text">email</code>, and <code class="language-text">password</code> fields:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"name"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-label"</span><span class="token operator">></span>Name<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"text"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"name"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control @error('name') is-invalid @enderror"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"name"</span> aria<span class="token operator">-</span>describedby<span class="token operator">=</span><span class="token string double-quoted-string">"nameHelp"</span> required<span class="token operator">></span> <span class="token operator"><</span>div id<span class="token operator">=</span><span class="token string double-quoted-string">"nameHelp"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-text"</span><span class="token operator">></span>Please enter both first <span class="token keyword">and</span> last name<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> @<span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'name'</span><span class="token punctuation">)</span> <span class="token operator"><</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"invalid-feedback"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$message</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> @enderror <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"date_of_birth"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-label"</span><span class="token operator">></span>Date of Birth<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"date"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"date_of_birth"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control @error('date_of_birth') is-invalid @enderror"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"date_of_birth"</span><span class="token operator">></span> @<span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'date_of_birth'</span><span class="token punctuation">)</span> <span class="token operator"><</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"invalid-feedback"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$message</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> @enderror <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-label"</span><span class="token operator">></span>Email address<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control @error('email') is-invalid @enderror"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> required<span class="token operator">></span> @<span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'email'</span><span class="token punctuation">)</span> <span class="token operator"><</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"invalid-feedback"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$message</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> @enderror <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"mb-3"</span><span class="token operator">></span> <span class="token operator"><</span>label <span class="token keyword">for</span><span class="token operator">=</span><span class="token string double-quoted-string">"password"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-label"</span><span class="token operator">></span>Password<span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"password"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"password"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control @error('password') is-invalid @enderror"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"password"</span> required<span class="token operator">></span> @<span class="token function">error</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'password'</span><span class="token punctuation">)</span> <span class="token operator"><</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"invalid-feedback"</span><span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$message</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> @enderror <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> </code></pre></div><p>The last thing we need to do is create a new route for the submission in <code class="language-text">routes/web.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/register'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">FormController</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'register'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'register'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Notice that we gave the route the name <code class="language-text">register</code>. Then, change the <code class="language-text">action</code> attribute of the <code class="language-text">form</code> element in <code class="language-text">resources/views/form.blade.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>form method<span class="token operator">=</span><span class="token string double-quoted-string">"POST"</span> action<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('register') }}"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"py-3 p-5"</span><span class="token operator">></span></code></pre></div><p>Our form is now ready to accept, validate data and show errors or success messages. Let’s test it out. If your server is not running, make sure to run it again.</p><p>Go to <code class="language-text">localhost:8000/register</code> and try at first to submit all the data correctly. You will see a success message on submission.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-02-at-4.14.21-PM.png" class="kg-image" alt="Beginner’s Guide to Validation in Laravel" loading="lazy" width="2874" height="1442"/></figure><p>Next, try to submit the form with data that will cause validation errors. For example, make the password less than 8 characters or enter a password confirmation that’s not similar to the password. You’ll see that after submission the Password field will have a red border and below it in red is the error message:</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-02-at-4.16.16-PM.png" class="kg-image" alt="Beginner’s Guide to Validation in Laravel" loading="lazy" width="2808" height="1390"/></figure><p>We can see now that the validation is working correctly! Since there was a validation issue, everything after the `validate` method didn’t execute, which is evident since we don’t see a success message. So, the `success` key was not written in the session and no message was shown because of that.</p><h2 id="show-old-values">Show Old Values</h2><p>When a user enters invalid data, a lot of times it’s either because they made a mistake or they’re not aware of what makes the data invalid. So, it’s good to show the old values that the user enters before the form submission. To get the old value of the input, we use the `old` method passing it the name of the input. </p><p>We’ll add that to the Name input:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"text"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"name"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control @error('name') is-invalid @enderror"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"name"</span> aria<span class="token operator">-</span>describedby<span class="token operator">=</span><span class="token string double-quoted-string">"nameHelp"</span> value<span class="token operator">=</span><span class="token string double-quoted-string">"{{ old('name') }}"</span> required<span class="token operator">></span></code></pre></div><p>The Date of Birth Input:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"date"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"date_of_birth"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control @error('date_of_birth') is-invalid @enderror"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"date_of_birth"</span> value<span class="token operator">=</span><span class="token string double-quoted-string">"{{ old('date_of_birth') }}"</span><span class="token operator">></span></code></pre></div><p>And finally, the Email input:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> name<span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string double-quoted-string">"form-control @error('email') is-invalid @enderror"</span> id<span class="token operator">=</span><span class="token string double-quoted-string">"email"</span> required value<span class="token operator">=</span><span class="token string double-quoted-string">"{{ old('email') }}"</span><span class="token operator">></span></code></pre></div><p>The password’s old value should not be shown. Now, try to submit the form again with some validation issues. You’ll see that the values you entered in the form before submission are repopulated in the form:</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-02-at-4.24.25-PM.png" class="kg-image" alt="Beginner’s Guide to Validation in Laravel" loading="lazy" width="2798" height="1368"/></figure><h2 id="create-custom-rule">Create Custom Rule</h2><p>Laravel provides out of the box a wide variety of rules that you can use for almost any case you need. However, there will be certain cases where these rules are not enough to validate the data you’re receiving. For that reason, you might need to create a custom rule that not only runs the validation you need but also behaves the same way the other validation rules built in Laravel do.</p><p>We’ll create a simple custom rule called Name that will check if the name has both a first and a last name separated by a space.</p><p>To create a custom rule, run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php artisan make:rule Name</code></pre></div><p>This will create the new class <code class="language-text">Name</code> in <code class="language-text">app/Rules/Name.php</code>. This class will have two methods. The first one is called <code class="language-text">passes</code> which receives the input name as a first parameter and the input’s value as a second parameter, then runs the validation logic needed and returns a boolean that determines whether the input value is valid or not. The second one is called <code class="language-text">message</code> which returns the validation message that should show if the input is not valid.</p><p>In our example, in the <code class="language-text">passes</code> method we’ll check if the value of the name input has at least 2 words separated by a space:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">passes</span><span class="token punctuation">(</span><span class="token variable">$attribute</span><span class="token punctuation">,</span> <span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">count</span><span class="token punctuation">(</span><span class="token function">explode</span><span class="token punctuation">(</span><span class="token string double-quoted-string">" "</span><span class="token punctuation">,</span> <span class="token variable">$value</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>And in the <code class="language-text">message</code> method we’ll return the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">message</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string single-quoted-string">'Name should have both first and last name.'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre></div><p>We’ll use the newly created rule in the validation of the form. To do that, we’ll need to change the value of the <code class="language-text">name</code> key in the second parameter of the <code class="language-text">validate</code> method to an array and add our new rule to the end of it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token string single-quoted-string">'name'</span> <span class="token operator">=></span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'required'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'min:1'</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Name</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> </code></pre></div><p>Now, go to the form (start the server first if it isn’t running) and try to submit the form with just a first name. You’ll see the error message that we return in the <code class="language-text">message</code> method under the name input:</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-02-at-4.42.18-PM.png" class="kg-image" alt="Beginner’s Guide to Validation in Laravel" loading="lazy" width="2770" height="1368"/></figure><p>And if you enter a first and last name separated by a space, you’ll see a success message. This means that our validation rules are all working correctly.</p><h2 id="conclusion">Conclusion</h2><p>In this tutorial, we went over how to use validation in Laravel using the built-in rules and using a custom rule. Validation is very important, as it ensures that all the data that are going into your system are of a specific necessary format or are secure. That’s why it’s essential to understand and master validation.</p>]]></content:encoded></item><item><title><![CDATA[How Small Business Owners Fail when Promoting Their Business]]></title><description><![CDATA[We are going to show you exactly how small business owners fail when promoting their business so you can make proactive choices to succeed.]]></description><link>https://blog.shahednasser.com/how-small-business-owners-fail-when-promoting-their-business/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eb2</guid><category><![CDATA[Business]]></category><dc:creator><![CDATA[Lori Gonzalez]]></dc:creator><pubDate>Tue, 20 Jul 2021 14:33:59 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/a49fdf64bce2ba600d76c9106897e938/the-blowup-UN4PadDppAU-unsplash-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/a49fdf64bce2ba600d76c9106897e938/the-blowup-UN4PadDppAU-unsplash-2.jpg" alt="How Small Business Owners Fail when Promoting Their Business"/><p>Many small business owners are not trained entrepreneurs or educated at business schools. More often than not they are someone with a great idea who wants to put it forward and take a leap of faith. This is an excellent plan. However, it does not always work out. If you are reading this, then it's your lucky day as we are going to show you exactly how small business owners fail when promoting their business so you can make proactive choices to succeed.</p><h2 id="self-education">Self-Education</h2><p>Rule number one is to know when you are bad at something in business. Self-education is a simple method to use to ensure that you learn all you need to know about starting out in the business sector. This does not mean that you have to go to university or take a distance learning course – though many people do. To start with, make use of the internet and study what you can by yourself.</p><p>There are sites that run free business courses. This is a fantastic way of beginning the journey. <a href="https://www.coursera.org/search?query=free+business&page=1">Coursera</a> is a particularly good site as it offers a wide selection of free unaccredited courses. If you want the accreditation, you do have to pay. Otherwise, you have the chance to get educated online by lecturers from top universities around the world. An invaluable free resource if you are limited by budget.</p><p>You may also wish to simply search Google for resources. Read <a href="https://www.candybar.co/blog/best-small-business-blogs/">blogs and articles</a> like this one to gain a broad understanding of the business sector and how you can promote yourself. You are likely to find there are methodologies and actions you can take that you never previously thought of, to make your business develop into a well-rounded venture.</p><h2 id="ask-people">Ask People</h2><p>Setting out as a new entrepreneur can be daunting. You may feel anxious that you do not know enough and try to hide it. Or you may feel like you don’t want someone to steal your ideas, so you don’t reach out for help. This is a big mistake that many new small business owners make when promoting their business. The issue here is that it cuts off the large support network in the business community.</p><p>When a business owner has achieved promotional success, they are often more than willing to assist others to do the same. The online world is a vast place. The competition is fierce between big brands, especially in advertising, but not the same with smaller ones. It may be just what you need and can lead to collaborations and friendships that are invaluably helpful in driving growth in a business.</p><h2 id="if-it%E2%80%99s-broken-%E2%80%93-fix-it">If It’s Broken – Fix It.</h2><p>Rectifying mistakes and learning from them is a major part of promotional success. This is something that a huge number of people starting out in business ignore. If you create an advertising plan and it receives no interactions on social media, change it.</p><p>Many small business owners set out with a brand or even a name of their business that does not captivate their audience. For example, if you sell coffee online. Consider how you market yourself to clearly sell coffee. Naming your business ‘Sam’s Beans’ isn’t going to instantly push the idea you sell coffee. If your audience can not immediately see what you sell, you are losing many customers and will have to invest a lot more time and money into advertising to achieve the same levels of success. A better name would be ‘Sam’s Online Coffee Shop’. It sounds almost boring, so many people do not follow this method. It can be a great way of jumping a gap in promoting yourself and your brand.</p><p>Similarly, your logo should be clear and obvious to your target audience. Many small business owners either forego a logo at all at the start or pay someone to design them a detailed logo. Keep it simple and be ready to change it if it does not work for your market. You can use a free <a href="https://logocreator.io/">logo creator</a> to design and download a logo for your business. This is perfect as it gives you the chance to test the waters with your branding before deciding on a final design.<br/></p><h2 id="conclusion">Conclusion</h2><p>Hopefully, this article can set you on the right track towards true business success. If you understand what you are missing and implement it as you learn, you will find the journey a progressive success.</p>]]></content:encoded></item><item><title><![CDATA[How to Add Keyboard Shortcuts In a Chrome Extension]]></title><description><![CDATA[In this tutorial, we'll go over how to add keyboard shortcuts in a Chrome extension Manifest versions 3 and 2.]]></description><link>https://blog.shahednasser.com/how-to-add-keyboard-shortcuts-in-a-chrome-extension/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eb1</guid><category><![CDATA[Browser Extensions]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 08 Jul 2021 18:04:19 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/bf2190a2ebcbc0919c959c33d0cc75a3/clay-banks-PXaQXThG1FY-unsplash--2---1-.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/bf2190a2ebcbc0919c959c33d0cc75a3/clay-banks-PXaQXThG1FY-unsplash--2---1-.jpg" alt="How to Add Keyboard Shortcuts In a Chrome Extension"/><p>Chrome Extensions have a lot of features and functionalities that help developers create extensions and tools with great user experience.</p><p>In this tutorial, we'll go over how to add keyboard shortcuts in a Chrome extension. This tutorial will cover how it can be done for both Manifest Versions 2 (MV2) and 3 (MV3). </p><p><em>Suggested Read: <a href="https://blog.shahednasser.com/chrome-extension-tutorial-migrating-to-manifest-v3-from-v2">Chrome Extension Tutorial: Migrating to Manifest V3 from V2</a></em></p><p>You can find the full code for this tutorial on <a href="https://github.com/shahednasser/chrome-commands-tutorial">this GitHub repository</a>.</p><hr><h3 id="creating-the-extension">Creating The Extension</h3><p>In case you already have an extension ready, you can skip this step. We'll quickly go over how to create a Chrome extension.</p><p><em>Suggested Read: Learn how to create a Chrome extension in the tutorial <a href="https://blog.shahednasser.com/chrome-extension-tutorial-replace-images-in-any-website-with-pikachu">Chrome Extension Tutorial — Replace Images in Any Website with Pikachu</a>.</em></p><p>To create a Chrome extension, first, create a directory that will hold all the extension files in it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> new-extension <span class="token builtin class-name">cd</span> new-extension</code></pre></div><p>Then, create a <code class="language-text">manifest.json</code> file with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Commands"</span><span class="token punctuation">,</span> <span class="token property">"version"</span><span class="token operator">:</span> <span class="token string">"0.0.1"</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Assign Keyboard Commands"</span><span class="token punctuation">,</span> <span class="token property">"manifest_version"</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token property">"icons"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"16"</span><span class="token operator">:</span> <span class="token string">"/assets/icon-16.png"</span><span class="token punctuation">,</span> <span class="token property">"32"</span><span class="token operator">:</span> <span class="token string">"/assets/icon-32.png"</span><span class="token punctuation">,</span> <span class="token property">"48"</span><span class="token operator">:</span> <span class="token string">"/assets/icon-48.png"</span><span class="token punctuation">,</span> <span class="token property">"128"</span><span class="token operator">:</span> <span class="token string">"/assets/icon-128.png"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span></code></pre></div><p>If you're creating a <strong>Manifest V2</strong> extension, make sure to change the manifest version:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"manifest_version"</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span></code></pre></div><p>Also, make sure to download the icons from the GitHub repository first, or add your own icons.</p><p>Then, go to <a href="chrome://extensions/">chrome://extensions/</a> on your Chrome browser, enable Developer Mode if you haven't from the top right, click on "Load unpacked" and choose the folder that you created for your extension. Once done, the extension will be added to your Chrome browser.</p><hr><h3 id="what-are-chrome-commands">What Are Chrome Commands</h3><p>Chrome commands allow an extension to register commands, or keyboard shortcuts, to provide ease of use for the users of that extension to perform certain actions through those shortcuts. An extension can have at most 4 commands.</p><p>There are two kinds of commands. A standard command and an action command. A standard command runs in the background script or service worker and has no access to the current page or tab opened. Standard commands trigger the event <code class="language-text">chrome.commands.onCommand</code>, and you can listen to it in your background script or service worker.</p><p>Action commands map the shortcuts to your extension's action (if <strong>MV3</strong>) or browser action or page action (if <strong>MV2</strong>). Action commands can have access to the current tab and can execute a script on the current page. Action commands <strong>do not </strong>trigger the event <code class="language-text">chrome.commands.onCommand</code>. Instead, in <strong>MV3</strong> they trigger <code class="language-text">chrome.action.onClicked</code> , and in <strong>MV2</strong> they trigger <code class="language-text">chrome.browserAction.onClicked</code> or <code class="language-text">chrome.pageAction.onClicked</code>.</p><p>Commands are defined in an extension's <code class="language-text">manifest.json</code> under the <code class="language-text">commands</code> key. Standard commands are defined in the following format:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"commands"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"firstCommand"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"suggested_key"</span><span class="token operator">:</span> <span class="token string">"CTRL+F"</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"My first command"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>Where <code class="language-text">suggested_key</code> can be an object or a string (we'll get to that in a bit) and <code class="language-text">description</code> is required.</p><p>Action commands are defined in the same way but under the <code class="language-text">_execute_action</code> key in MV3, or <code class="language-text">_execute_browser_action</code> or <code class="language-text">_execute_page_action</code> keys in MV2:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"commands"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"_execute_action"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"suggested_key"</span><span class="token operator">:</span> <span class="token string">"CTRL+F"</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"My first command"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p><code class="language-text">description</code> for action commands is optional.</p><h3 id="suggested-key">Suggested Key</h3><p>Some of the keys that are allowed to be used are: <code class="language-text">Ctrl</code>, <code class="language-text">Alt</code>, <code class="language-text">Shift</code>, <code class="language-text">0...9</code>, and <code class="language-text">A...Z</code>. For a full list of keys, you can see them in the <a href="https://developer.chrome.com/docs/extensions/reference/commands/#supported-keys">chrome.commands reference</a>.</p><p><code class="language-text">suggested_key</code> can either be a string or an object. If a string, then the same shortcut will be applied for all Operating Systems. In this case, certain keys will be replaced with their equivalent on the Operating Systems. This means that <code class="language-text">Ctrl</code> on Mac OS will be substituted by <code class="language-text">Command</code>.</p><p>To specify the shortcut for an operating system, you should pass an object where the key is the operating system's name. The allowed keys are <code class="language-text">default</code> which applies the shortcut to all operating systems not listed in the object, <code class="language-text">chromeos</code>, <code class="language-text">linux</code>, <code class="language-text">mac</code>, and <code class="language-text">windows</code>.</p><p>If you want to use <code class="language-text">Ctrl</code> on Mac instead of <code class="language-text">Command</code>, you can use <code class="language-text">MacCtrl</code> for the value of <code class="language-text">mac</code> in the object:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"suggested_key"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"default"</span><span class="token operator">:</span> <span class="token string">"Ctrl+F"</span><span class="token punctuation">,</span> <span class="token property">"mac"</span><span class="token operator">:</span> <span class="token string">"MacCtrl+F"</span> <span class="token punctuation">}</span></code></pre></div><p>This will make the shortcut <code class="language-text">Ctrl+F</code> for all operating systems, but for Mac instead of the conventional <code class="language-text">Command</code> substitute, it will use the <code class="language-text">Ctrl</code> key on Mac.</p><p>It should be noted that the value for the keyboard shortcuts is <strong>case-sensitive</strong>. If you set the value to <code class="language-text">CTRL+F</code> instead of <code class="language-text">Ctrl+F</code>, the shortcut will not be registered.</p><h3 id="global-shortcuts">Global Shortcuts</h3><p>By default, keyboard shortcuts are executed only when the Chrome browser is in focus. To allow shortcuts to work even when Chrome is in the background, you can make the command "global" by adding the <code class="language-text">global</code> key in the definition:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"commands"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"first"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"suggested_key"</span><span class="token operator">:</span> <span class="token string">"Ctrl+Shift+F"</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"First command"</span><span class="token punctuation">,</span> <span class="token property">"global"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>Global shortcuts are very limited in the amount of keys you can use in <code class="language-text">suggested_key</code> to make sure your shortcut does not overlap with a system shortcut. For that reason, the format should be <code class="language-text">Ctrl+Shift+[0...9]</code>.</p><p>If the shortcut is already defined and you later set it to global, upon testing it I noticed that the shortcut will not be updated. To update it, you will need to remove and reinstall the extension.</p><hr><h3 id="adding-an-action-command">Adding an Action Command</h3><p>We'll first add an action command. The action command will toggle "Dark Mode" on the current website. We'll do it in a very basic way, which is just changing the background color to black and text color to white, as this is not the purpose of this tutorial.</p><p><strong>Define The Command</strong></p><p>Let's first define the action command. It will be triggered at the press of <code class="language-text">Ctrl+Shift+L</code>. </p><p><strong>MV3</strong></p><p>For <strong>MV3</strong>, the definition will be:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"commands"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"_execute_action"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"suggested_key"</span><span class="token operator">:</span> <span class="token string">"Ctrl+Shift+L"</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Toggle dark body"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span></code></pre></div><p>As we are adding an Action command, we need to also add an <code class="language-text">action</code> key<strong>:</strong></p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"action"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p><strong>MV2</strong></p><p>For <strong>MV2 </strong>we just need to change <code class="language-text">_execute_action</code> to <code class="language-text">_execute_browser_action</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"commands"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"_execute_browser_action"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"suggested_key"</span><span class="token operator">:</span> <span class="token string">"Ctrl+Shift+L"</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Toggle dark body"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span></code></pre></div><p>and add a <code class="language-text">browser_action</code> key<strong>:</strong></p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"browser_action"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>This will define our command that toggles dark mode at the press of <code class="language-text">Ctrl+Shift+L</code>. Make sure that the <code class="language-text">suggested_key</code> value is correct as it is <strong>case-sensitive</strong>. If it's incorrect, the shortcut will not be registered.</p><p><strong>Add Event Listeners</strong></p><p>Next, we need to listen to when these keys are pressed. Inside the listener, we need to execute a Javascript code that will just toggle the background color and text color of the document's body.</p><p><strong>MV3</strong></p><p>To do that, first, add a service worker:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"service_worker"</span><span class="token operator">:</span> <span class="token string">"background.js"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>Then, in the service worker or background script, we'll add a listener to handle the press of the keys. In the service worker, we'll add a listener to <code class="language-text">chrome.action.onClicked</code> event:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>action<span class="token punctuation">.</span>onClicked<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">tab</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//TODO toggle dark mode in the tab</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Inside the listener, we'll use <a href="https://developer.chrome.com/docs/extensions/reference/scripting/#method-executeScript">chrome.scripting.executeScript</a><strong>. </strong><code class="language-text">executeScript</code> accepts an object of options including <code class="language-text">tabId</code> for the id of the tab to execute the script on and <code class="language-text">function</code> for the Javascript function to execute. Add in the service worker the following function:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">toggleDark</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">'data-ext-dark'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'data-ext-dark'</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>style<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token string">'#000'</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>style<span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token string">'#fff'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'data-ext-dark'</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>style<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token string">'#fff'</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>style<span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token string">'#000'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>Then, inside the listener we created earlier, we'll use <code class="language-text">executeScript</code> to execute the function on the current tab:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>scripting<span class="token punctuation">.</span><span class="token function">executeScript</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">target</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token literal-property property">tabId</span><span class="token operator">:</span> tab<span class="token punctuation">.</span>id<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token operator">:</span> toggleDark <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p><strong>MV2</strong></p><p>If you're creating an <strong>MV2 </strong>extension, you need to add a background script instead:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"background.js"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"persistent"</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>In the background script, we'll add a listener to <code class="language-text">chrome.browserAction.onClicked</code> event:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>browserAction<span class="token punctuation">.</span>onClicked<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">tab</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//TODO toggle dark mode in the tab</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p><code class="language-text">chrome.scripting</code> is not compatible with <strong>MV2</strong>. Instead, we'll use <a href="https://developer.chrome.com/docs/extensions/reference/tabs/#method-executeScript">chrome.tabs.executeScript</a>. This method accepts 2 arguments, the first one the id of the tab to execute the script on, and the second is an object of options including the <code class="language-text">file</code> option which allows you to specify a Javascript file to inject into the page and execute. So, create a new file called <code class="language-text">toggleDark.js</code> in the root of the extension with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">'data-ext-dark'</span><span class="token punctuation">)</span> <span class="token operator">||</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">'data-ext-dark'</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">'false'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'data-ext-dark'</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>style<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token string">'#000'</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>style<span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token string">'#fff'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'data-ext-dark'</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>style<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token string">'#fff'</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>style<span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token string">'#000'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>And in the listener we created earlier, use <code class="language-text">chrome.tabs.executeScript</code> to run the code in <code class="language-text">toggleDark.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>browserAction<span class="token punctuation">.</span>onClicked<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">tab</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> chrome<span class="token punctuation">.</span>tabs<span class="token punctuation">.</span><span class="token function">executeScript</span><span class="token punctuation">(</span>tab<span class="token punctuation">.</span>id<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">file</span><span class="token operator">:</span> <span class="token string">'toggleDark.js'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p><strong>Adding Permissions</strong></p><p>Now we're ready to handle when the shortcut is pressed. There's one last thing we need to do which is add permissions. Permissions are defined in <code class="language-text">manifest.json</code> and include a set of permissions that the user has to allow for the extension to run.</p><p><strong>MV3</strong></p><p>If you've been following along with the <strong>MV3 </strong>instructions, then you'll need two permissions: <code class="language-text">activeTab</code> to access the current tab and <code class="language-text">scripting</code> to use the <code class="language-text">chrome.scripting</code> API. So, add the following in <code class="language-text">manifest.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"permissions"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"activeTab"</span><span class="token punctuation">,</span> <span class="token string">"scripting"</span><span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div><p><strong>MV2</strong></p><p>As for <strong>MV2, </strong>we'll need the <code class="language-text">activeTab</code> permission to access the current tab and <code class="language-text">tabs</code> to use the <code class="language-text">chrome.tabs</code> API. So, add the following in <code class="language-text">manifest.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"permissions"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"activeTab"</span><span class="token punctuation">,</span> <span class="token string">"tabs"</span><span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div><p><strong>Testing</strong></p><p>Let's test our code. First, go to <code class="language-text">chrome://extensions</code> and refresh the extension. Then, in an open tab (if you're creating an MV2 extension you'll need to refresh the page), press <code class="language-text">Ctrl+Shift+L</code>, and the document's body background color will change to black and the text to white. Remember that we're taking a simple approach to dark mode, so obviously it will not actually look good. If you keep pressing the same shortcut, it will toggle between light and dark mode.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-08-at-6.54.33-PM.png" class="kg-image" alt="How to Add Keyboard Shortcuts In a Chrome Extension" loading="lazy"/></figure><p>If it doesn't work, make sure that <code class="language-text">Ctrl+Shift+P</code> in your <code class="language-text">manifest.json</code> is written correctly, as this is case-sensitive. Also, it should be noted that if other extensions that were installed previously use this shortcut, they'll have precedence to use the shortcut. Similarly, if the shortcut is used by the browser or your operating system, then it will not be triggered. So, if the command does not work for you, try changing the shortcut in the manifest, then refresh the extension and try again.</p><hr><h3 id="adding-a-standard-command">Adding a Standard Command</h3><p>Next, we'll add a standard command. The standard command we'll create will use the shortcut <code class="language-text">Ctrl+Shift+P</code> to print to the console of the service worker or background script "Hello there!". It will run as long as Chrome is in focus, regardless of what page or tab is open.</p><p>This section is the same for both <strong>MV3 </strong>and <strong>MV2</strong>, so you can follow along regardless of what version your extension is. </p><p>In <code class="language-text">manifest.json</code>, add another command under the <code class="language-text">commands</code> key:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"commands"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">//...</span> <span class="token property">"hello"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"suggested_key"</span><span class="token operator">:</span> <span class="token string">"Ctrl+Shift+P"</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Say Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span></code></pre></div><p>Then, in the service worker or background script, add a listener to the <code class="language-text">chrome.commands.onCommand</code> event:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>commands<span class="token punctuation">.</span>onCommand<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">command</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//TODO handle event</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>In the listener, we'll first check which command is triggered. This is necessary once you have more than one standard command, as they all trigger this same event.</p><p>The <code class="language-text">command</code> argument passed is the name of the command. So, if the user presses <code class="language-text">Ctrl+Shift+P</code>, the value for <code class="language-text">command</code> will be <code class="language-text">hello</code>.</p><p>If the <code class="language-text">command</code> is <code class="language-text">hello</code>, we'll log to the console "Hello there!":</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span>command <span class="token operator">===</span> <span class="token string">'hello'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Hello there!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>That's it. Go to <a href="chrome://extensions">chrome://extensions</a> and refresh the extension. Then, for <strong>MV3 </strong>extensions click on "Inspect views service worker"</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-08-at-7.10.25-PM.png" class="kg-image" alt="How to Add Keyboard Shortcuts In a Chrome Extension" loading="lazy"/></figure><p>For <strong>MV2 </strong>extensions click on "Inspect views background page"</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-08-at-7.10.31-PM.png" class="kg-image" alt="How to Add Keyboard Shortcuts In a Chrome Extension" loading="lazy"/></figure><p>This will open the devtools for the service worker or background script. Click on the Console tab. Now, try clicking the shortcut <code class="language-text">Ctrl+Shift+P</code> and you'll see "Hello there!" logged in the console.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-08-at-7.13.14-PM.png" class="kg-image" alt="How to Add Keyboard Shortcuts In a Chrome Extension" loading="lazy"/></figure><p>If it doesn't work, make sure that <code class="language-text">Ctrl+Shift+P</code> in your <code class="language-text">manifest.json</code> is written correctly, as this is case-sensitive. Also, it should be noted that if other extensions that were installed previously use this shortcut, they'll have precedence to use the shortcut. Similarly, if the shortcut is used by the browser or your operating system, then it will not be triggered. So, if the command does not work for you, try changing the shortcut in the manifest, then refresh the extension and try again.</p><hr><h3 id="making-a-command-global">Making a Command Global</h3><p>In this section, we'll create a global standard command that when the user presses <code class="language-text">Ctrl+Shift+8</code>, it will log to the console of the service worker or background script the current date.</p><p>This section is the same for both <strong>MV3 </strong>and <strong>MV2</strong>, so you can follow along regardless of what version your extension is.</p><p>To make a command global, we just need to add the key <code class="language-text">global</code> to its definition in <code class="language-text">manifest.json</code> and set it to true:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"date"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"suggested_key"</span><span class="token operator">:</span> <span class="token string">"Ctrl+Shift+8"</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Show Date"</span><span class="token punctuation">,</span> <span class="token property">"global"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span></code></pre></div><p>Then, in your service worker or background script, add an else block to the previous if statement that checked if the command name was "hello". In the else block, we'll log to the console the current date:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>commands<span class="token punctuation">.</span>onCommand<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">command</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>command <span class="token operator">===</span> <span class="token string">'hello'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Hello there!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Date: "</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toDateString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Our new command is ready. During development, I noticed that the global command, whether it's a newly added command or an older command that we added the <code class="language-text">global</code> key to it, later on, the shortcut was not added or updated unless the extension was removed and re-loaded. So, make sure to do that.</p><p>Then, open the console for the service worker or background script as mentioned in the previous section. If you now change to any window that's not your Chrome browser and press <code class="language-text">Ctrl+Shift+8</code>, then go back to the console for the service worker or background script, you'll see that the date is logged.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-08-at-7.19.23-PM.png" class="kg-image" alt="How to Add Keyboard Shortcuts In a Chrome Extension" loading="lazy"/></figure><p>Again, if the command does not work, make sure that the command in the manifest is correct as it is <strong>case-sensitive</strong>. Also, if this command is used by your system for another shortcut, you'll need to change it to something else.</p><hr><h3 id="conclusion-next-steps">Conclusion: Next Steps</h3><p>As you have noticed while going through this tutorial, if an extension that was added prior to yours uses the same shortcut, your shortcuts will not be registered, so they will not work. To avoid that, you can check if your shortcuts are all added on installing the extension, and if any are missing you can notify the user that they can set the shortcuts in their Chrome browser on <a href="chrome://extensions/shortcuts">chrome://extensions/shortcuts</a>. For more information and an example on how to do that, check <a href="https://developer.chrome.com/docs/extensions/reference/commands/#verify-commands-registered">the example on chrome.command reference</a>.</p></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[How to Use Magento With Bootstrap, React, and Vue.js]]></title><description><![CDATA[In this tutorial, we'll go over how to use Bootstrap, React, and Vue.js with Magento 2.]]></description><link>https://blog.shahednasser.com/how-to-use-magento-with-bootstrap-react-and-vue-js/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eb0</guid><category><![CDATA[Magento]]></category><category><![CDATA[CSS]]></category><category><![CDATA[React]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 03 Jul 2021 14:27:30 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/a7015eb32c0e1e93ca707c1f20af21fa/mohammad-rahmani-0JvWk8ox_rQ-unsplash--1-.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/a7015eb32c0e1e93ca707c1f20af21fa/mohammad-rahmani-0JvWk8ox_rQ-unsplash--1-.jpg" alt="How to Use Magento With Bootstrap, React, and Vue.js"/><p>Magento is one of the leading e-commerce frameworks. It provides so many features out of the box, making it everything any merchant or seller might need. However, development in Magento can be a hassle, as it is not easy to learn and it's not easy to integrate with some of the leading frontend frameworks or libraries.</p><p>In this tutorial, we'll go over how to use Bootstrap, React, and Vue.js with Magento 2.</p><hr><h3 id="prerequisites-create-a-theme">Prerequisites: Create a Theme</h3><p>This tutorial will add the libraries or frameworks in a new theme. However, if you need to add them to a module it's pretty much the same process.</p><p>If you don't have a theme created, we'll quickly go over how to create a theme. First, create the directory <code class="language-text">app/design/frontend/VENDOR/THEME_NAME</code> where <code class="language-text">VENDOR</code> is your own company or your name, and <code class="language-text">THEME_NAME</code> is the name of the theme.</p><p>Then, in the theme directory create the file <code class="language-text">theme.xml</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>theme</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:framework:Config/etc/theme.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>THEME_NAME<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>parent</span><span class="token punctuation">></span></span>Magento/blank<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>parent</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>theme</span><span class="token punctuation">></span></span> </code></pre></div><p>Make sure to change <code class="language-text">THEME_NAME</code> to the name of your theme. </p><p>Then, create the file <code class="language-text">registration.php</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Component<span class="token punctuation">\</span>ComponentRegistrar</span><span class="token punctuation">;</span> <span class="token class-name static-context">ComponentRegistrar</span><span class="token operator">::</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token class-name static-context">ComponentRegistrar</span><span class="token operator">::</span><span class="token constant">THEME</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'frontend/VENDOR_NAME/THEME_NAME'</span><span class="token punctuation">,</span> <span class="token constant">__DIR__</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><p>Make sure to change <code class="language-text">VENDOR_NAME</code> and <code class="language-text">THEME_NAME</code> accordingly.</p><p>Finally, create <code class="language-text">composer.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"VENDOR_NAME/THEME_NAME"</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"N/A"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"magento2-theme"</span><span class="token punctuation">,</span> <span class="token property">"license"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"OSL-3.0"</span><span class="token punctuation">,</span> <span class="token string">"AFL-3.0"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"config"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"sort-packages"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"version"</span><span class="token operator">:</span> <span class="token string">"100.4.2"</span><span class="token punctuation">,</span> <span class="token property">"require"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"php"</span><span class="token operator">:</span> <span class="token string">"~7.3.0||~7.4.0"</span><span class="token punctuation">,</span> <span class="token property">"magento/framework"</span><span class="token operator">:</span> <span class="token string">"103.0.*"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"autoload"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"files"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"registration.php"</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>Again, make sure to change <code class="language-text">VENDOR_NAME</code> and <code class="language-text">THEME_NAME</code> accordingly.</p><p>Now go to your Magento admin and login. Then, go to Content -> Configuration. Click on Edit for the Default Store View. Now, choose your theme from the "Applied Theme" dropdown and click Save Configuration.</p><hr><h3 id="using-bootstrap-with-magento">Using Bootstrap with Magento</h3><p>Bootstrap is one of the most famous CSS libraries out there. Bootstrap is used in so many websites that we use every day. Using it makes web development easier, so figuring out how to use it with Magento is useful.</p><p>There's a small difference between using Bootstrap 5 and prior versions. I'll point it out when we get to it.</p><p>First, <a href="https://getbootstrap.com/docs/5.0/getting-started/download/">download Bootstrap</a> with the version you want. If you are downloading Bootstrap v5.x, you need to <a href="https://unpkg.com/@popperjs/core@2">download Popper.js version 2</a>. However, if you are downloading Bootstrap v4.6 or earlier, you need to <a href="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js">download Popper.js version 1</a>.</p><p>Then, extract the downloaded Bootstrap ZIP. It will have <code class="language-text">css</code> and <code class="language-text">js</code> directories. Move <code class="language-text">css/bootstrap.min.css</code> to your theme directory and place it in <code class="language-text">THEME_NAME/web/css</code>. Also, move <code class="language-text">js/bootstrap.min.js</code> to your theme directory and place it in <code class="language-text">THEME_NAME/web/js</code>. Finally, place <code class="language-text">popper.min.js</code> that you downloaded in <code class="language-text">THEME_NAME/web/js</code>.</p><p>Then, in the root of the theme directory create <code class="language-text">requirejs-config.js</code>. The content will be slightly different depending on the version of Bootstrap you're using.</p><p>If you're using Bootstrap >= 5.0:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">var</span> config <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">shim</span><span class="token operator">:</span><span class="token punctuation">{</span> <span class="token literal-property property">bootstrap</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">deps</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'jquery'</span><span class="token punctuation">,</span> <span class="token string">'@popperjs/core'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'*'</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">bootstrap</span><span class="token operator">:</span> <span class="token string">'js/bootstrap.min'</span><span class="token punctuation">,</span> <span class="token string-property property">'@popperjs/core'</span><span class="token operator">:</span> <span class="token string">'js/popper.min'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div><p>If you're using prior versions:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">var</span> config <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">shim</span><span class="token operator">:</span><span class="token punctuation">{</span> <span class="token literal-property property">bootstrap</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">deps</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'jquery'</span><span class="token punctuation">,</span> <span class="token string">'popper.js'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'*'</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">bootstrap</span><span class="token operator">:</span> <span class="token string">'js/bootstrap.min'</span><span class="token punctuation">,</span> <span class="token string-property property">'popper.js'</span><span class="token operator">:</span> <span class="token string">'js/popper.min'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div><p>The reason behind the difference is that in Bootstrap 5, <code class="language-text">bootstrap.min.js</code> requires <code class="language-text">@popperjs/core</code>, whereas in prior versions <code class="language-text">bootstrap.min.js</code> requires <code class="language-text">popper.js</code>.</p><p>If you're not familiar with what <code class="language-text">requirejs-config.js</code> does, it basically defines the scripts for later use in our theme or module using RequireJS. the <code class="language-text">map</code> key allows us to define the libraries we want to use under certain keys to refer to them in other places. <code class="language-text">shim</code> allows defining what the library might depend on. In Bootstrap's case, it depends on jQuery and Popper.js</p><p>The next step is adding the CSS file for Bootstrap in the <code class="language-text">head</code> tag of our pages. To do that, create in your theme's directory the file <code class="language-text">Magento_Theme/layout/default_head_block.xml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token prolog"><?xml version="1.0"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>page</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:framework:View/Layout/etc/page_configuration.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>css</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>css/bootstrap.min.css<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>page</span><span class="token punctuation">></span></span></code></pre></div><p> Let's test that both the CSS file and JS files are working correctly. Create in your theme's directory the file <code class="language-text">Magento_Theme/layout/default.xml</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token prolog"><?xml version="1.0"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>page</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:framework:View/Layout/etc/page_configuration.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>referenceContainer</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>content<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>block</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>test-bootstrap<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento\Framework\View\Element\Template<span class="token punctuation">"</span></span> <span class="token attr-name">template</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento_Theme::test-bootstrap.phtml<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>referenceContainer</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>page</span><span class="token punctuation">></span></span></code></pre></div><p>This will add a block to the content container of our pages. Then, create the file <code class="language-text">Magento_Theme/templates/test-bootstrap.phtml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="phtml"><pre class="language-phtml"><code class="language-phtml"><button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Tooltip on top"> Hover me </button> <script> require(['jquery', 'bootstrap'], function ($) { $('[data-bs-toggle="tooltip"]').tooltip(); }); </script></code></pre></div><p>This will show a button with a tooltip, which will test both Bootstrap and Popper's functionalities.</p><p>The integration with Bootstrap is done now. To test it out, first, use <code class="language-text">setup:static-content:deploy</code> command after clearing the <code class="language-text">var/cache</code>, <code class="language-text">var/view_preprocessed</code>, <code class="language-text">var/page_cache</code>, <code class="language-text">generated</code>, and <code class="language-text">pub/static/frontend</code> directories:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php bin/magento setup:static-content:deploy -f</code></pre></div><p><em>Recommended read - Learn how to compile front-end changes in Magento 2 easily: <a href="https://blog.shahednasser.com/how-to-make-your-front-end-development-faster-in-magento-2-using-grunt">How to Make Your Front-End Development Faster in Magento 2 Using Grunt</a></em></p><p>If you go now to the home page, you should see a button that will show a tooltip when you hover it.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-03-at-4.09.58-PM.png" class="kg-image" alt="How to Use Magento With Bootstrap, React, and Vue.js" loading="lazy"/></figure><hr><h3 id="using-react-with-magento">Using React with Magento</h3><p>In this tutorial, we'll cover the easiest way to integrate React with Magento. If you search a little online, you'll find a lot of methods using Grunt and other methods. In this one, we'll show the most basic way to integrate React with Magento 2.</p><p>First, download the production builds for <a href="https://unpkg.com/react@17.0.2/umd/react.production.min.js">React</a> and <a href="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js">ReactDom</a> and place them in <code class="language-text">THEME_NAME/web/js</code>. Then, create <code class="language-text">requirejs-config.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">var</span> config <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'*'</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'react'</span><span class="token operator">:</span> <span class="token string">'js/react.production.min'</span><span class="token punctuation">,</span> <span class="token string-property property">'react-dom'</span><span class="token operator">:</span> <span class="token string">'js/react-dom.production.min'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div><p>As mentioned above, <code class="language-text">require-config.js</code> allows us to define the libraries or frameworks and refer to them by the key specified. </p><p>Let's first create a <code class="language-text">Button</code> component. Create the file <code class="language-text">THEME_NAME/web/js/components/Button.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">define</span> <span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'react'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">React</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> e <span class="token operator">=</span> React<span class="token punctuation">.</span>createElement<span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Button</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">e</span><span class="token punctuation">(</span><span class="token string">'button'</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token string">'Button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> Button<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Note that as we're not using <a href="https://babeljs.io/">Babel</a> or <a href="https://webpack.js.org/">Webpack</a>, we can't write components using <a href="https://reactjs.org/docs/introducing-jsx.html">JSX</a>. So, we'll have to use the function <code class="language-text">React.createElement</code>. For simplicity, we first store it in a new variable:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">var</span> e <span class="token operator">=</span> React<span class="token punctuation">.</span>createElement<span class="token punctuation">;</span></code></pre></div><p>The function takes at least three parameters. The first is the tag name of the element to create, or if you're using a React component you pass the component. The second parameter is either an object of props to pass to the component (for example, <code class="language-text">{className: 'btn'}</code>) or <code class="language-text">null</code> for no props. Starting from the third parameter, you can pass children elements each as a parameter to the function.</p><p>Finally, we return the component to be used in other components:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> Button<span class="token punctuation">;</span></code></pre></div><p>Now, we'll create the main component <code class="language-text">App</code> that will render other components. Create <code class="language-text">THEME_NAME/web/js/App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">require</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'react'</span><span class="token punctuation">,</span> <span class="token string">'react-dom'</span><span class="token punctuation">,</span> <span class="token string">'js/components/Button'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">React<span class="token punctuation">,</span> ReactDom<span class="token punctuation">,</span> Button</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> e <span class="token operator">=</span> React<span class="token punctuation">.</span>createElement<span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">e</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token function">e</span><span class="token punctuation">(</span>Button<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> ReactDom<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token function">e</span><span class="token punctuation">(</span>App<span class="token punctuation">)</span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'root'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Note that we assigned <code class="language-text">React.createElement</code> to a new variable <code class="language-text">e</code>. Then, in the <code class="language-text">App</code> component we're rendering a <code class="language-text">div</code> element that has <code class="language-text">Button</code> as a child component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token function">e</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token function">e</span><span class="token punctuation">(</span>Button<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Notice that in order to use the <code class="language-text">Button</code> component, in the first parameter of <code class="language-text">require</code> we passed in the array <code class="language-text">js/components/Button</code>, which is the path of the component. If you want to reference the components in an easier manner, you can add them to the <code class="language-text">map</code> object in <code class="language-text">requirejs-config.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'*'</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">//...</span> <span class="token string-property property">'Button'</span><span class="token operator">:</span> <span class="token string">'js/components/Button'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>Then, in the <code class="language-text">require</code> function when you want to use the <code class="language-text">Button</code> component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">require</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span><span class="token punctuation">,</span> <span class="token string">'Button'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token operator">...</span><span class="token punctuation">)</span></code></pre></div><p>Let's use the components we created. Create <code class="language-text">Magento_Theme/layout/default.xml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token prolog"><?xml version="1.0"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>page</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:framework:View/Layout/etc/page_configuration.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>js/App.js<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>referenceContainer</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>content<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>block</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>test-react<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento\Framework\View\Element\Template<span class="token punctuation">"</span></span> <span class="token attr-name">template</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento_Theme::test-react.phtml<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>referenceContainer</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>page</span><span class="token punctuation">></span></span></code></pre></div><p>We're loading <code class="language-text">js/App.js</code> in the head of the page, and we're adding a new block in the <code class="language-text">content</code> container. Remember, this is for testing purposes, so you don't need to add it to the <code class="language-text">default.xml</code>. You can add it to whatever layout or page you want.</p><p>Next, create <code class="language-text">Magento_Theme/templates/test-react.phtml</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="phtml"><pre class="language-phtml"><code class="language-phtml"><div id="root"></div></code></pre></div><p>The integration is done. To test it out, first use <code class="language-text">setup:static-content:deploy</code> command after clearing the <code class="language-text">var/cache</code>, <code class="language-text">var/view_preprocessed</code>, <code class="language-text">var/page_cache</code>, <code class="language-text">generated</code>, and <code class="language-text">pub/static/frontend</code> directories:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php bin/magento setup:static-content:deploy -f</code></pre></div><p><em>Recommended read - Learn how to compile front-end changes in Magento 2 easily: <a href="https://blog.shahednasser.com/how-to-make-your-front-end-development-faster-in-magento-2-using-grunt">How to Make Your Front-End Development Faster in Magento 2 Using Grunt</a></em></p><p>After that's done, go to the home page and you should see a button:</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-03-at-4.38.09-PM.png" class="kg-image" alt="How to Use Magento With Bootstrap, React, and Vue.js" loading="lazy"/></figure><hr><h3 id="using-vue-with-magento">Using Vue with Magento</h3><p>Vue is another popular Javascript framework. Integrating it with Magento is pretty easy.</p><p>First, download the latest version of Vue, either <a href="https://vuejs.org/js/vue.js">development</a> or <a href="https://vuejs.org/js/vue.min.js">production</a>. Once it downloads, place the JS file in <code class="language-text">THEME_NAME/web/js</code>.</p><p>Next, create <code class="language-text">requirejs-config.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">var</span> config <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'*'</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'vue'</span><span class="token operator">:</span> <span class="token string">'js/vue.min'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div><p>And with that, we're ready to use Vue!</p><p>Let's create a <code class="language-text">btn</code> component. Create the file <code class="language-text">THEME_NAME/web/js/components/Btn.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">define</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'vue'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">Vue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> Vue<span class="token punctuation">.</span><span class="token function">component</span><span class="token punctuation">(</span><span class="token string">'btn'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">props</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'text'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">template</span><span class="token operator">:</span> <span class="token string">'<button>{{ text }}</button>'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This will create the <code class="language-text">btn</code> component. Next, create <code class="language-text">THEME_NAME/web/js/App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">require</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'vue'</span><span class="token punctuation">,</span> <span class="token string">'js/components/btn'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">Vue<span class="token punctuation">,</span> btn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">btn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">new</span> <span class="token class-name">Vue</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">el</span><span class="token operator">:</span> <span class="token string">'#root'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This will get the <code class="language-text">btn</code> component we create it to register it then create our Vue app.</p><p>To use the Vue app, create <code class="language-text">THEME_NAME/Magento_Theme/layouts/default.xml</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token prolog"><?xml version="1.0"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>page</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:framework:View/Layout/etc/page_configuration.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>js/App.js<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>referenceContainer</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>content<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>block</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>test-vue<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento\Framework\View\Element\Template<span class="token punctuation">"</span></span> <span class="token attr-name">template</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento_Theme::test-vue.phtml<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>referenceContainer</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>page</span><span class="token punctuation">></span></span></code></pre></div><p>This will add the <code class="language-text">App.js</code> script we created to the <code class="language-text">head</code> of the page, and will add a new block to the content container. Remember, this is for testing purposes, so you don't need to add it to the <code class="language-text">default.xml</code>. You can add it to whatever layout or page you want.</p><p>Finally, create <code class="language-text">THEME_NAME/Magento_Theme/templates/test-vue.phtml</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="phtml"><pre class="language-phtml"><code class="language-phtml"><div id="root"> <btn text="Button"></btn> </div></code></pre></div><p>The integration is done. To test it out, first use <code class="language-text">setup:static-content:deploy</code> command after clearing the <code class="language-text">var/cache</code>, <code class="language-text">var/view_preprocessed</code>, <code class="language-text">var/page_cache</code>, <code class="language-text">generated</code>, and <code class="language-text">pub/static/frontend</code> directories:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php bin/magento setup:static-content:deploy -f</code></pre></div><p><em>Recommended read - Learn how to compile front-end changes in Magento 2 easily: <a href="https://blog.shahednasser.com/how-to-make-your-front-end-development-faster-in-magento-2-using-grunt">How to Make Your Front-End Development Faster in Magento 2 Using Grunt</a></em></p><p>After that's done, go to the home page and you should see a button:</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-07-03-at-5.08.48-PM.png" class="kg-image" alt="How to Use Magento With Bootstrap, React, and Vue.js" loading="lazy"/></figure><hr><h3 id="conclusion">Conclusion</h3><p>In this tutorial, we went over how to integrate some of the famous and widely used frameworks and libraries with Magento 2. Hopefully, this will help you expand your Magento 2 development!</p></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Useful Tailwind CSS Libraries and Plugins]]></title><description><![CDATA[In this article, we'll go over some libraries and plugins that will be useful during your development using Tailwind CSS. ]]></description><link>https://blog.shahednasser.com/useful-tailwind-css-libraries-and-plugins/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eaf</guid><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[CSS]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 30 Jun 2021 17:31:58 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/aae7d37ee06dfcecc2166b56baa74cd4/temple-cerulean-tP8ZwlCF8og-unsplash--1-.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/aae7d37ee06dfcecc2166b56baa74cd4/temple-cerulean-tP8ZwlCF8og-unsplash--1-.jpg" alt="Useful Tailwind CSS Libraries and Plugins"/><p><a href="https://tailwindcss.com/">Tailwind CSS</a> is a CSS framework that's designed to make creating reusable components easier, facilitate development by minimizing the repeated CSS you'll have to write yourself, and optimize the size of the final compiled CSS file by <a href="https://tailwindcss.com/docs/optimizing-for-production">tree-shaking unused classes</a>.</p><p>In this article, we'll go over some libraries and plugins that will be useful during your development using Tailwind CSS. </p><hr><h2 id="daisyui"><a href="https://daisyui.com/">DaisyUI</a></h2><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-30-at-7.40.48-PM.png" class="kg-image" alt="Useful Tailwind CSS Libraries and Plugins" loading="lazy"/></figure><p><a href="https://daisyui.com/">DaisyUI</a> uses Tailwind's utility classes to provide you with components and utility classes that you'll frequently need in different projects. So, instead of creating the same <code class="language-text">Button</code> component in your project with the following code:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>inline-block px-4 py-3 text-sm font-semibold text-center text-white uppercase transition duration-200 ease-in-out bg-indigo-500 rounded-md cursor-pointer hover:bg-indigo-600<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Button<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> </code></pre></div><p>You can just use the classes <code class="language-text">btn btn-primary</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn-primary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Button<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span></code></pre></div><p>This uses the familiar <a href="https://getbootstrap.com/">Bootstrap</a> class names into Tailwind CSS. You can also customize the components and utility classes using any of Tailwind's utility classes.</p><hr><h2 id="heroicons"><a href="https://heroicons.com/">Heroicons</a></h2><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-30-at-7.46.45-PM.png" class="kg-image" alt="Useful Tailwind CSS Libraries and Plugins" loading="lazy"/></figure><p><a href="https://heroicons.com/">Heroicons</a> is an official library from Tailwind CSS. Heroicons provide a large set of icons you can use in React and Vue. You can also just copy the SVG of each icon from the website directly, without having to use the library or in case you're not using React and Vue.</p><p>It's pretty simple and handy. For example, to use a User icon:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>UserIcon className<span class="token operator">=</span><span class="token string">"h-5 w-5 text-blue-500"</span><span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>As you can see, you can also add Tailwind's utility classes and it will work perfectly.</p><hr><h2 id="windmill-react-ui"><a href="https://windmillui.com/react-ui">Windmill React UI</a></h2><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-30-at-8.03.54-PM.png" class="kg-image" alt="Useful Tailwind CSS Libraries and Plugins" loading="lazy"/></figure><p><a href="https://windmillui.com/react-ui">Windmill React UI</a> provides UI components in React that use Tailwind's utility classes. Similar to DaisyUI, Windmill React UI provides frequently used components to be used in your projects. However, the difference is that instead of providing the components as utility classes like DaisyUI, it provides the components as React components. This can be easier if your project is a React project.</p><hr><h2 id="tailwind-typography"><a href="https://github.com/tailwindlabs/tailwindcss-typography">Tailwind Typography</a></h2><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-30-at-8.08.25-PM.png" class="kg-image" alt="Useful Tailwind CSS Libraries and Plugins" loading="lazy"/></figure><p><a href="https://github.com/tailwindlabs/tailwindcss-typography">Tailwind Typography</a> is an official Tailwind plugin that allows you to style text neatly and beautifully. In addition, you can make your text's size responsive and add beautiful styling to the text with different colors.</p><hr><h2 id="twin"><a href="https://github.com/ben-rogerson/twin.macro">Twin</a></h2><p><a href="https://github.com/ben-rogerson/twin.macro">Twin</a> allows you to combine Tailwind CSS with css-in-js easily. Using Twin allows you to conditionally apply stylings, use Sass stylings, create styled components and more.</p><p>Here's an example of how you would conditionally apply a style with Twin:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> tw <span class="token keyword">from</span> <span class="token string">'twin.macro'</span> <span class="token keyword">const</span> <span class="token function-variable function">Input</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> hasHover <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>input css<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">[</span>tw<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">border</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> hasHover <span class="token operator">&&</span> tw<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">hover:border-black</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span></code></pre></div><hr><h2 id="tailwind-css-line-clamp"><a href="https://github.com/tailwindlabs/tailwindcss-line-clamp">Tailwind CSS Line Clamp</a></h2><p><a href="https://github.com/tailwindlabs/tailwindcss-line-clamp">Tailwind CSS Line Clamp</a> is another Tailwind official plugin. It allows you to truncate text based on the number of lines you want to appear. For example, if you want a text to show only the first 4 lines and truncate the rest:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>p <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"line-clamp-4"</span><span class="token operator">></span> Lorem ipsum dolor sit amet<span class="token punctuation">,</span> consectetur adipiscing elit<span class="token punctuation">.</span> Pellentesque ultrices<span class="token punctuation">,</span> urna ut interdum posuere<span class="token punctuation">,</span> lectus nulla mattis massa<span class="token punctuation">,</span> sed rutrum quam mi a ex<span class="token punctuation">.</span> Sed nec lacus ut justo porta vehicula et quis diam<span class="token punctuation">.</span> Vestibulum vitae nulla <span class="token keyword">in</span> elit pretium volutpat <span class="token keyword">in</span> a orci<span class="token punctuation">.</span> Quisque nec efficitur metus<span class="token punctuation">.</span> Fusce dictum convallis volutpat<span class="token punctuation">.</span> Donec porta dolor ac erat porttitor<span class="token punctuation">,</span> eu rhoncus ante vehicula<span class="token punctuation">.</span> Praesent varius ante arcu<span class="token punctuation">,</span> fermentum pellentesque ex fermentum id<span class="token punctuation">.</span> Nam consequat venenatis auctor<span class="token punctuation">.</span> Praesent placerat<span class="token punctuation">,</span> ante id venenatis mollis<span class="token punctuation">,</span> leo sem eleifend mi<span class="token punctuation">,</span> <span class="token keyword">in</span> rutrum massa lorem id enim<span class="token punctuation">.</span> Nunc varius enim libero<span class="token punctuation">,</span> <span class="token keyword">in</span> tincidunt ex porttitor vitae<span class="token punctuation">.</span> Nunc non tellus enim<span class="token punctuation">.</span> In quis turpis id arcu vulputate feugiat eu ut nibh<span class="token punctuation">.</span> Aenean vel justo velit<span class="token punctuation">.</span> Vivamus venenatis lectus non odio fermentum malesuada<span class="token punctuation">.</span> Ut vel risus quis mi tincidunt posuere<span class="token punctuation">.</span> Fusce tempor rutrum nibh ac cursus<span class="token punctuation">.</span> <span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span></code></pre></div><hr><h2 id="material-tailwind"><a href="https://material-tailwind.com/">Material Tailwind</a></h2><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-30-at-8.18.29-PM.png" class="kg-image" alt="Useful Tailwind CSS Libraries and Plugins" loading="lazy"/></figure><p><a href="https://material-tailwind.com/">Material Tailwind</a> is another UI components library that provides easy-to-use React components to use in your projects. It's pretty similar to Windmill React UI, however, it has a wider set of UI components and colors with various options as well.</p><hr><h3 id="conclusion">Conclusion</h3><p>As Tailwind CSS keeps rising in popularity, we'll see even more helpful and useful libraries and plugins for the framework. Make sure to share with others good resources about Tailwind CSS to help them in their projects, as well!</p></hr></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Easily Create a Free Logo Using DesignEvo]]></title><description><![CDATA[DesignEvo allows you to create beautiful logos in a matter of minutes with an easy-to-use interface and a wide variety of fonts, colors, shapes, and icons.]]></description><link>https://blog.shahednasser.com/easily-create-a-free-logo-using-designevo/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eae</guid><category><![CDATA[Reviews]]></category><category><![CDATA[Design]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Fri, 25 Jun 2021 05:46:06 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/16742e5641871fb041b84afcc46aed53/Untitled-design.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/16742e5641871fb041b84afcc46aed53/Untitled-design.png" alt="Easily Create a Free Logo Using DesignEvo"/><p><em>Snatch a 20% promo code at the end of this article!</em></p><p>The logo is the most important part of any brand. A good logo helps people identify and remember your brand when done correctly. Creating a logo can be a hassle sometimes, especially for small businesses and projects. You might need something quick and easy, but you don’t have the necessary tools or even the creativity for it.</p><p>Especially as developers. How many times did you get this brilliant new idea, you even purchased a domain name for it, but you couldn’t figure out how to get a good logo without the hassle. Sometimes you start a new open source project and you’re unsure how to get a good, free logo for it.</p><p>This is where DesignEvo comes along. DesignEvo allows you to create beautiful logos in a matter of minutes. It provides existing templates based on different topics and categories that your project or business might fall under, easy to use interface to customize them, and downloadable formats to be used everywhere you might need.</p><p>To showcase DesignEvo’s features and what it has to offer, I attempted to create a logo for my blog. I’ve never really used a logo for my blog, so it was a nice way to see how it all works and show my readers as well! You can actually see the logo in action right now as the favicon of the blog.</p><h2 id="wide-variety-of-templates">Wide Variety of Templates</h2><p><br>The first step to creating a logo on DesignEvo is to go to their <a href="https://www.designevo.com/logo-maker/" rel="noreferrer nofollow noopener">Logo Maker</a> page. There, you’ll see a huge collection of logos, each belonging to different categories, which you can filter.</br></p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-23-at-8.03.08-PM.png" class="kg-image" alt="Easily Create a Free Logo Using DesignEvo" loading="lazy"/></figure><p>You can also search by keyword. As my blog is a technical blog, I searched for“code” and the results were pretty nice as well.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-23-at-6.33.29-PM.png" class="kg-image" alt="Easily Create a Free Logo Using DesignEvo" loading="lazy"/></figure><p>The wide variety of different options allowed me to not only pick what I liked the most but also understand which ones I didn’t find fitting. This helps in narrowing down what are the best options.</p><p>In the end, I picked this one as a starting point:</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-23-at-6.34.13-PM.png" class="kg-image" alt="Easily Create a Free Logo Using DesignEvo" loading="lazy"/></figure><h2 id="easy-to-use-customization-interface">Easy-to-Use Customization Interface</h2><p>When you find a logo of your liking, you can click on“Customize” to start making it your own.</p><p>The customization interface is very easy to use. It has options for the text, the logo icon/shape, and the background as well.</p><p><strong>Fonts</strong></p><p>For the text, there’s a big collection of fonts to use. You can use any of these fonts with no limitations. As my blog uses Quicksand as the main font, I chose it for the font of the text.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-23-at-6.37.00-PM.png" class="kg-image" alt="Easily Create a Free Logo Using DesignEvo" loading="lazy"/></figure><p><strong>Shapes</strong></p><p>There’s also a huge collection of shapes you can add to your logo. From frames to banners and symbols, you have unlimited creativity easily accessible.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-23-at-6.41.13-PM.png" class="kg-image" alt="Easily Create a Free Logo Using DesignEvo" loading="lazy"/></figure><p>You can also make changes to the colors of any of the shapes. As my blog generally adopts a darker color scheme, I decided to make the circle’s background blue and the color of the icon inside white. This was easy to use and do. DesignEvo also provides a set of nice colors to choose from, so you don’t have to worry too much about finding the right color.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-23-at-6.46.38-PM.png" class="kg-image" alt="Easily Create a Free Logo Using DesignEvo" loading="lazy"/></figure><p><strong>Background Color</strong></p><p>Another thing you can do in the customization interface changes the background color. Again, there’s a wide set of colors you can choose from, so you don’t have to worry about finding the color scheme yourself. You can also choose to keep the logo transparent, which was what I did.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-23-at-6.46.46-PM.png" class="kg-image" alt="Easily Create a Free Logo Using DesignEvo" loading="lazy"/></figure><p><strong>Save Design</strong></p><p>If you’re working on the design, but you don’t want to lose the changes you’ve made in the customization interface, you can save the design to make any changes to it later on. To do that, you’ll need to create a new account either using social login or using your email. Once you create an account, you can access your custom logo design at any point to make changes to it.<br/></p><h2 id="download-and-use-the-logo">Download and Use The Logo</h2><p>Once you’re done customizing your logo, or if you want to test the logo, you can do so just by clicking on “Download” in the toolbar. When you do, you’ll be asked to either download the logo for free or choose the Basic or Plus plan.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-23-at-6.49.18-PM.png" class="kg-image" alt="Easily Create a Free Logo Using DesignEvo" loading="lazy"/></figure><p>Now is the big question, should I just use the free plan, or do I need one of the paid plans? To see the differences, I tried both free download and downloading with the Plus plan.</p><p><strong>Using The Free Plan</strong></p><p>When you download the logo with the free plan, you’ll get a ZIP file containing three files. The logo in PNG format, the logo in JPG format, and a text file containing attribution details.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-23-at-6.51.00-PM.png" class="kg-image" alt="Easily Create a Free Logo Using DesignEvo" loading="lazy"/></figure><p>Part of the free plan is that you need to attribute the logo to DesignEvo, either by sharing it on social media or linking to it on your website.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-23-at-6.49.55-PM.png" class="kg-image" alt="Easily Create a Free Logo Using DesignEvo" loading="lazy"/></figure><p>It should also be noted that both logo formats are 300x300 at most, and they’re not transparent. So, if your logo needs to be used as transparent, this can cause an issue. <br>In most use cases, this can be enough. However, this does not provide the full power you can have with the Plus plan.</br></p><p><strong>Using The Plus Plan</strong></p><p>When you download the logo using the Plus plan you’ll also get a ZIP file, however, even upon first look at it without looking through it you can tell how much better it is.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-23-at-6.52.45-PM.png" class="kg-image" alt="Easily Create a Free Logo Using DesignEvo" loading="lazy"/></figure><p>First, you get all the fonts you’ve used in the logo. This is very helpful if you want to use the font somewhere else along with the logo, or if you want to edit the logo outside DesignEvo.</p><p>But how would you edit the logo outside DesignEvo? In the downloaded ZIP, you can also see a “vector” directory, which holds the logo as a PDF and as SVG. Using these files and the fonts provided, you can edit the logo in most editing software.</p><p>In the downloaded ZIP, you can also find high-resolution PNG and JPG images that can be transparent (if you set the background to transparent in the customization interface). The resolution of the images is 5000x5000, which makes the 300x300 in the free plan no match for it.</p><p>Finally, you can find the original file as well, which is the image in both PNG and JPG formats in the size you choose in the customization interface.<br>In addition to all the files you get when downloading a logo using the free plan, you don’t need to credit the logo to DesignEvo. This makes the logo yours.</br></p><h2 id="edit-whenever">Edit Whenever</h2><p>After downloading the logo, you can still edit it at any point on DesignEvo by going to “My Logos” in your account. If you’ve already purchased the Plus plan on that logo, you can still download it using the plus plan later.</p><p>In my case, I realized I don’t need to include my name in the logo. I just want the logo to be an icon. So, I changed the size of the logo to fit only the icon and removed my name from it. I was able to download it again with the plus plan that I already purchased, and I got all the files I got before as well.<br/></p><h2 id="multiple-platforms">Multiple Platforms</h2><p>To make using DesignEvo even easier and better, not only can you use it on their website, but they also have <a href="https://www.designevo.com/for-mobile/" rel="noreferrer nofollow noopener">Apps</a> for both Android and iOS. This means that you can create and edit logos on the go easily.<br/></p><h2 id="summary">Summary</h2><p>Let’s summarize everything into a set of pros and cons:</p><p><strong>Pros</strong></p><ol><li>Choose from thousands of logo templates, each having different categories which makes them easy to filter or search through.</li><li>Customize the logo using a simple interface, providing a nice experience.</li><li>Wide-set of fonts to use with no limitations.</li><li>Beautiful color schemes to choose from.</li><li>Variety of shapes and icons to use in your logo.</li><li>A portable platform that allows you to access your design from all different types of devices.</li><li>Has a free plan other than the paid plans.</li><li>Download your logo within minutes and use it everywhere.</li></ol><p><strong>Cons</strong></p><p>The biggest con would probably be some limitations in the free plan, which makes it hindering in some use cases. For example, if you need the logo transparent or you can’t give attribution to DesignEvo. In this case, you’ll probably need the basic or plus plans.<br/></p><h2 id="grab-the-deal-">Grab the deal!</h2><p>Nothing better than deals! After this long review, you’ve probably realized you might need the basic or plus plans more than ever. So, exclusively for my readers, I’m bringing you a promo code to get 20% off!<br>The promo code is <strong>ShahedEvo20OFF.</strong> Here’s how you can use it:<br/></br></p><ol><li>After designing your logo and you’re ready to download, choose the Basic or Plus plan.</li><li>In the checkout page, click on “Have a Coupon” link, and enter the coupon <strong>ShahedEvo20OFF.</strong></li><li>Enter your payment details and enjoy your basic/plus plan 20% off!</li></ol><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/redeem.png" class="kg-image" alt="Easily Create a Free Logo Using DesignEvo" loading="lazy"/></figure>]]></content:encoded></item><item><title><![CDATA[How to Log Messages Into Custom Files In Laravel]]></title><description><![CDATA[In this tutorial, we'll go over how to create custom log files in Laravel based on different configurations, for example, different message levels.]]></description><link>https://blog.shahednasser.com/how-to-log-messages-into-custom-files-in-laravel/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ead</guid><category><![CDATA[Laravel]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 22 Jun 2021 16:19:33 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/64bc1fdd24ccf0dc9856581c06029c82/photo-1599507593499-a3f7d7d97667--1--min.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/64bc1fdd24ccf0dc9856581c06029c82/photo-1599507593499-a3f7d7d97667--1--min.jpg" alt="How to Log Messages Into Custom Files In Laravel"/><p>By default, Laravel aggregates all log messages into one file which is in <code class="language-text">storage/logs/laravel.log</code> relative to the root of the project. In this tutorial, we'll go over how to create custom log files in Laravel based on different configurations, for example, different message levels.</p><p><em>This tutorial uses Laravel 8 and PHP 7.3.</em></p><h2 id="installation">Installation</h2><p>If you already have Laravel installed, you can skip this step. If not, follow along.</p><p>First, download <a href="https://getcomposer.org/download/">Composer</a> if you don't have it on your system.</p><p>Then, run the following command to create the Laravel project:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">composer</span> create-project laravel/laravel custom-logs</code></pre></div><p>This command will download Laravel and all its dependencies, and copy <code class="language-text">.env.sample</code> to <code class="language-text">.env</code>.</p><p>Now change the directory to the project and start the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> custom-logs php artisan serve</code></pre></div><p>If you go to <code class="language-text">localhost:8000</code> (or whatever port Laravel uses after running the above command), you'll see that Laravel is working.</p><p><em>If you get an error about permissions, change the permission of the <code class="language-text">storage</code> directory to be readable.</em></p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-22-at-6.08.33-PM.png" class="kg-image" alt="How to Log Messages Into Custom Files In Laravel" loading="lazy"/></figure><h2 id="understanding-laravel-s-logs">Understanding Laravel's Logs</h2><p>Laravel has different channels for logging. Channels are different ways to log a message. For example, the <code class="language-text">slack</code> channel will log the messages to <a href="http://slack.com">Slack</a>, whereas the <code class="language-text">single</code> channel just puts all messages in one file (by default, at <code class="language-text">storage/logs/laravel.log</code>). Laravel handles logs using the <a href="https://github.com/Seldaek/monolog">Monolog</a> library.</p><p>The configuration for Laravel's logs are found in <code class="language-text">config/logging.php</code>. There, you'll find the default channel:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token string single-quoted-string">'default'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'LOG_CHANNEL'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'stack'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></code></pre></div><p>By default, Laravel uses the <code class="language-text">stack</code> channel, which allows you to use many channels at once. We will get into how it works later in this tutorial.</p><p>You'll also find an array of <code class="language-text">channels</code> each having a similar structure:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token string single-quoted-string">'single'</span> <span class="token operator">=></span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'single'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'path'</span> <span class="token operator">=></span> <span class="token function">storage_path</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'logs/laravel.log'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'level'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'LOG_LEVEL'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'debug'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div><p>Each channel definition has the following configurations:</p><ol><li><code class="language-text">driver</code>: which driver it uses. It can be one of the <a href="https://laravel.com/docs/8.x/logging#available-channel-drivers">default drivers</a> like <code class="language-text">single</code> or <code class="language-text">slack</code>, or it can be a custom driver you create yourself.</li><li><code class="language-text">path</code>: The path to the log file the output is in if there's any.</li><li><code class="language-text">level</code>: the minimum level the logged message should have to be handled by this channel.</li><li><code class="language-text">bubble</code>: should the logged message bubble to other channels after being handled by this channel.</li><li><code class="language-text">locking</code>: Should the log file be locked before writing to it.</li><li><code class="language-text">permission</code>: The permission that the log file should have when it's created.</li></ol><p>There are other configurations as well depending on the channel driver. For example, the <code class="language-text">slack</code> driver takes <code class="language-text">username</code> as a configuration.</p><h3 id="understanding-levels">Understanding Levels</h3><p>The levels of the log messages can be emergency, alert, critical, error, warning, notice, info, and debug (sorted from most critical to the least critical). When you assign a level for a channel, it will only log messages of that level or higher. For example, a channel that has the level set to "warning" will only log messages of level warning, error, critical, alert, or emergency. Anything below "warning" (notice, info, and debug) will not be handled by this channel.</p><h3 id="how-to-log-messages">How to Log Messages</h3><p>On your website, you can use the <code class="language-text">Log</code> facade to log messages of different levels:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Log</span><span class="token punctuation">;</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">emergency</span><span class="token punctuation">(</span><span class="token variable">$message</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">alert</span><span class="token punctuation">(</span><span class="token variable">$message</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">critical</span><span class="token punctuation">(</span><span class="token variable">$message</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token variable">$message</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">warning</span><span class="token punctuation">(</span><span class="token variable">$message</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">notice</span><span class="token punctuation">(</span><span class="token variable">$message</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token variable">$message</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token variable">$message</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>The <code class="language-text">Log</code> facade will use the default channel you chose in <code class="language-text">config/logging.php</code>. So, you only need to make configuration changes there without having to do it every time you want to log a message.</p><h2 id="multiple-files-based-on-levels">Multiple Files Based On Levels</h2><p>In this section, we'll see how to create different files depending on the level of the message. We'll log all messages having the level "error" or higher into <code class="language-text">storage/logs/errors.log</code>, and all messages having a lower level than that into <code class="language-text">storage/logs/debug.log</code>. This way, it will be easier to track errors in our Laravel project and separate them from debug messages that might not be as important.</p><p>First, add to the <code class="language-text">channels</code> array in <code class="language-text">config/logging.php</code> a new channel <code class="language-text">custom_errors</code> with the following configuration:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token string single-quoted-string">'custom_error'</span> <span class="token operator">=></span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'single'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'level'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'error'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'path'</span> <span class="token operator">=></span> <span class="token function">storage_path</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'logs/errors.log'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'bubble'</span> <span class="token operator">=></span> <span class="token constant boolean">false</span> <span class="token punctuation">]</span></code></pre></div><p>This channel uses the <code class="language-text">single</code> driver, meaning that it will aggregate all the messages in one file. That file will be <code class="language-text">storage/logs/errors.log</code> as defined in the <code class="language-text">path</code> configuration of the channel. We've set the level to <code class="language-text">error</code>, and we've set <code class="language-text">bubble</code> to false. This means that once the message is logged by this channel, the message will not propagate to any of the other channels.</p><p>Next, add another new channel <code class="language-text">custom_debug</code> with the following configuration:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token string single-quoted-string">'custom_debug'</span> <span class="token operator">=></span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'single'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'level'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'debug'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'path'</span> <span class="token operator">=></span> <span class="token function">storage_path</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'logs/debug.log'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div><p>This channel also uses the <code class="language-text">single</code> drive, as it also aggregates the messages into one file, the file being <code class="language-text">storage/logs/debug.log</code> as defined by the <code class="language-text">path</code> configuration. Its level is set to <code class="language-text">debug</code>, meaning it will log any message having the level <code class="language-text">debug</code> or higher.</p><p>What's left is to make sure our default channel uses these newly created channels. Go to the <code class="language-text">stack</code> channel in the <code class="language-text">channels</code> array, which is usually the first item in the array. It should look something like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"> <span class="token string single-quoted-string">'stack'</span> <span class="token operator">=></span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'stack'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'channels'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'single'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'ignore_exceptions'</span> <span class="token operator">=></span> <span class="token constant boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div><p>It uses the <code class="language-text">stack</code> driver, which as mentioned earlier allows using multiple channels. These channels can be set in the <code class="language-text">channels</code> configuration, which by default is an array having one item <code class="language-text">single</code>. For that reason Laravel by default logs all messages in <code class="language-text">storage/logs/laravel.log</code>. </p><p>What we need to do is change the <code class="language-text">channels</code> configuration of the <code class="language-text">stack</code> channel to use the custom logs we created earlier:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token string single-quoted-string">'stack'</span> <span class="token operator">=></span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'stack'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'channels'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'custom_error'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'custom_debug'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'ignore_exceptions'</span> <span class="token operator">=></span> <span class="token constant boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div><p>One important detail is that <code class="language-text">custom_error</code> precedes <code class="language-text">custom_debug</code> in the array. As <code class="language-text">custom_debug</code> has the level <code class="language-text">debug</code>, it can actually log all levels of messages, including error messages. We only want it to log messages having a level lower than "error", so, we give <code class="language-text">custom_error</code> a higher priority, as it only logs messages having a level "error" or higher and will prevent the message from bubbling since the <code class="language-text">bubble</code> configuration is set to <code class="language-text">false</code>.</p><p>Let's test it out. If you're using a fresh installation of Laravel, you can just go to <code class="language-text">routes/web.php</code> and add the following in the main route available:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Log</span><span class="token punctuation">;</span> <span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string double-quoted-string">"this is info message"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string double-quoted-string">"This is error message"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'welcome'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>You can add the same lines to any other route or controller:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token comment">//inside controller or route</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string double-quoted-string">"this is info message"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string double-quoted-string">"This is error message"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Then, navigate to the route you added the code to. In the first case, it will be <code class="language-text">localhost:8000</code>. After that, let's check if the messages were logged in the correct files.</p><p>At the root of your project, check the files that are currently in <code class="language-text">storage/logs</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">ls</span> storage/logs</code></pre></div><p>You should see <code class="language-text">debug.log</code> and <code class="language-text">errors.log</code> among other files (if there are any others). </p><p>Let's check the content of <code class="language-text">debug.log</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">cat</span> storage/logs/debug.log</code></pre></div><p>And it should have the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">[TIME] local.INFO: this is info message</code></pre></div><p>Where <code class="language-text">TIME</code> is the date and time this message is logged. Notice that only the message having the level "info" is logged, meaning it was handled by the "custom_debug" channel.</p><p>Next, let's check the content of <code class="language-text">errors.log</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">cat</span> storage/logs/errors.log</code></pre></div><p>It should have the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">[TIME] local.ERROR: This is error message</code></pre></div><p>Where <code class="language-text">TIME</code> is the date and time this message is logged. Notice that only the message having the level "error" is logged, meaning it was handled by the "custom_errors" channel.</p><p>So, our configuration was successful! We will now have 2 separate logs, one for debug messages and one for error messages.</p><h2 id="conclusion">Conclusion</h2><p>Customizing how logs are handled can be pretty easy with Laravel. Other than the example we made, you can try to also use a different <code class="language-text">driver</code> for your log channel like <code class="language-text">slack</code> or <code class="language-text">daily</code>, and you can add as many channels as you want to the <code class="language-text">stack</code> channel.</p>]]></content:encoded></item><item><title><![CDATA[Google Introduces Search Console Insights for Content Creators]]></title><description><![CDATA[Google introduced Search Console Insights to provide an improved experience for content creators and help them better understand their audience and traffic.]]></description><link>https://blog.shahednasser.com/google-introduces-search-console-insights-for-content-creators/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eac</guid><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 21 Jun 2021 17:02:07 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/e7518dfa32984c2b6e85e1c23ac4f05b/photo-1560472354-b33ff0c44a43--1--min.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/e7518dfa32984c2b6e85e1c23ac4f05b/photo-1560472354-b33ff0c44a43--1--min.jpg" alt="Google Introduces Search Console Insights for Content Creators"/><p>As a content creator, it's very important to understand how your content is performing. Monitoring which content has the most views, which topics perform best over time, which channels result in more traffic, and more is essential in choosing what audience your content attracts and what you should write about next.</p><p>To make things easier for content creators, Google introduced <a href="https://search.google.com/search-console/insights/about">Search Console Insights</a>, a combination between <a href="https://search.google.com/search-console/about">Search Console</a> and <a href="/p/7ef28c67-c28d-4a47-bce2-71d876d9ba7a/%20Google%20Analyticshttps://analytics.google.com%20%E2%80%BA%20analytics%20%E2%80%BA%20web">Google Analytics</a> to provide an improved experience for content creators and help them better understand their audience and traffic.</p><p>Users will first see a notice on their Search Console telling them about how they can discover the content across the web. The link will lead them to their Search Console Insights.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-06-21-at-7.00.01-PM.png" class="kg-image" alt="Google Introduces Search Console Insights for Content Creators" loading="lazy"/></figure><p>When clicking on the link, you'll see all different kinds of analytics, including your website's all-time pageviews, highest-performing pages, top traffic channels, and more.</p><p>As a content creator, you will be able to see some information that surely was in your google analytics or search console accounts but was not as highlighted or easily noticeable.</p><p>Search Console Insights take the statistics related to the search queries on the Search Console and the statistics related to your website's traffic on Google Analytics, then generates the report that is specific to you as a content creator.</p><p>The Search Console Insights allow you to focus on how the newest content is performing by specifying a section solely dedicated to it and making it the first thing you see when you access it. This is another way of easily viewing the data regarding your newest posts or pages.</p><p>It also showcases your most popular content and even adds some badges to it that make you notice which content has the highest average duration or which is trending the most.</p><p>Another aspect Google Search Console Insights sheds light on is search queries. It shows the top 5 search queries and most trending search queries. This is very essential for content creators, as it's important to ensure your content is always getting traffic and that usually comes from search engines. Understanding the search queries that lead to your content the most helps you realize what your next content should be.</p><p>An additional aspect that Search Console Insight focuses on is referral links and social media referrals. This can also be very helpful as it helps you understand which channels and mediums generate the most traffic for your website, helping you to focus on them the most or improve your presence on the channels and mediums your website lacks.</p><p>Google Search Console Insights does not necessarily bring new data that's different than that of Search Console and Google Analytics, but it sheds light on the information that's most important to content creators and helps them understand the data in a new light that's more suitable for them.</p>]]></content:encoded></item><item><title><![CDATA[How to Take Screenshots in Chrome Extension]]></title><description><![CDATA[In this tutorial, we'll cover how to take a screenshot in a Chrome extension and save it on the user's machine.]]></description><link>https://blog.shahednasser.com/how-to-take-screenshots-in-chrome-extension/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382eab</guid><category><![CDATA[Browser Extensions]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 07 Jun 2021 15:28:48 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/e7b786c1095d434670e646e2afd6405a/photo-1509966756634-9c23dd6e6815.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/e7b786c1095d434670e646e2afd6405a/photo-1509966756634-9c23dd6e6815.jpg" alt="How to Take Screenshots in Chrome Extension"/><p>In this tutorial, we'll cover how to take a screenshot in a Chrome extension and save it on the user's machine. This tutorial requires some beginner skills in Javascript.</p><p>We'll create an extension that allows the user to take a screenshot just by clicking the icon of the toolbar. The user can choose to take a screenshot of the entire screen, just a window, or the current tab.</p><p>Note that this extension will be using Manifest V3. I'll provide some hints about the differences between V3 and V2 throughout the tutorial, but if you want to know more about the differences between the two versions you can check out <a href="https://blog.shahednasser.com/chrome-extension-tutorial-migrating-to-manifest-v3-from-v2/">this tutorial</a>.</p><p>You can find the code for this tutorial on <a href="https://github.com/shahednasser/chrome-screenshot-tutorial">this GitHub Repository</a>.</p><hr><h2 id="creating-the-extension">Creating The Extension</h2><p>We will not get into details on how to create a Chrome Extension, as it is not the purpose. If you need to learn more details about it you can check out <a href="https://blog.shahednasser.com/chrome-extension-tutorial-replace-images-in-any-website-with-pikachu/">this tutorial</a>.</p><p>Create <code class="language-text">manifest.json</code> in the root of your extension directory with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Screenshots"</span><span class="token punctuation">,</span> <span class="token property">"version"</span><span class="token operator">:</span> <span class="token string">"0.0.1"</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Take screenshots"</span><span class="token punctuation">,</span> <span class="token property">"manifest_version"</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token property">"action"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"default_title"</span><span class="token operator">:</span> <span class="token string">"Take a Screenshot"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"icons"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"16"</span><span class="token operator">:</span> <span class="token string">"/assets/icon-16.png"</span><span class="token punctuation">,</span> <span class="token property">"32"</span><span class="token operator">:</span> <span class="token string">"/assets/icon-32.png"</span><span class="token punctuation">,</span> <span class="token property">"48"</span><span class="token operator">:</span> <span class="token string">"/assets/icon-48.png"</span><span class="token punctuation">,</span> <span class="token property">"128"</span><span class="token operator">:</span> <span class="token string">"/assets/icon-128.png"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>The icons we are using for this extension are by <a href="https://iconscout.com/contributors/bzzricon">BZZRICON Studio</a> on <a href="https://iconscout.com/">Iconscout</a>.</p><p>For Manifest V2, make sure the <code class="language-text">manifest_version</code> is set to 2:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"manifest_version"</span><span class="token operator">:</span> <span class="token number">2</span></code></pre></div><p>and make sure to replace <code class="language-text">action</code> with <code class="language-text">browser_action</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"browser_action"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"default_title"</span><span class="token operator">:</span> <span class="token string">"Take a Screenshot"</span> <span class="token punctuation">}</span></code></pre></div><p>Then, create a zip of, go to <a href="chrome://extensions">chrome://extensions</a>, enable Developer Mode from the top right if it isn't enabled, click "Load Unpacked" from the buttons on the left, and choose the directory of the extension. Our extension will be added successfully.</p><h2 id="add-service-worker-or-background-script-">Add Service Worker (or Background Script)</h2><p>To detect when a user clicks on the extension's icon, we need to attach an event listener to <code class="language-text">chrome.action.onClicked</code>. To do that, we need to add a service worker (or background script for V2).</p><p>To add a service worker, add the following in <code class="language-text">manifest.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"service_worker"</span><span class="token operator">:</span> <span class="token string">"background.js"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>Or the following for V2:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"background.js"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"persistent"</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>Next, create <code class="language-text">background.js</code> in the root of the extension with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>action<span class="token punctuation">.</span>onClicked<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">tab</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>for V2 it should be the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>browserAction<span class="token punctuation">.</span>onClicked<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">tab</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Note that if you don't have the <code class="language-text">action</code> key in <code class="language-text">manifest.json</code>, you will not be able to add a listener to <code class="language-text">onClicked</code>. </p><p>Next, we'll start the "take screenshot" process. To do that, we'll use the <a href="https://developer.chrome.com/docs/extensions/reference/desktopCapture/">Desktop Capture API</a>. In particular, we'll use the method <code class="language-text">chrome.desktopCapture.chooseDesktopMedia</code> which takes 3 parameters: The first is an array of strings of capture sources, which can be "screen", "window", "tab", and "audio". The second parameter is the target tab which is optional, however, in some cases if the target tab is not passed Chrome crashes. The third parameter is a callback that returns the stream id which we'll use later to get a screenshot.</p><p>add the following inside the listener:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>desktopCapture<span class="token punctuation">.</span><span class="token function">chooseDesktopMedia</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token string">"screen"</span><span class="token punctuation">,</span> <span class="token string">"window"</span><span class="token punctuation">,</span> <span class="token string">"tab"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> tab<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">streamId</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//check whether the user canceled the request or not</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>streamId <span class="token operator">&&</span> streamId<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Notice that we're passing in the first parameter "screen", "window", and "tab" as the allowed source types. The second parameter is the <code class="language-text">tab</code> parameter passed to the listener, and the third is the callback function. We're checking if <code class="language-text">streamId</code> is not empty since it will be <code class="language-text">empty</code> if the user cancels the request.</p><p>Before we can use this though, we need to add some permissions in the <code class="language-text">manifest.json</code>. Permissions allow the user to understand what the extension is doing and agree to it before it is installed in their browser.</p><p>Add the following to <code class="language-text">manifest.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"permissions"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"desktopCapture"</span><span class="token punctuation">,</span> <span class="token string">"tabs"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div><p>The reason we also need the <code class="language-text">tabs</code> permission is because if we don't have the permission, the <code class="language-text">tab</code> object passed to the <code class="language-text">onClicked</code> event listener will not have the <code class="language-text">url</code> parameter which is required for <code class="language-text">chooseDesktopMedia</code> when passing that tab as a parameter.</p><p>So, if you reload the extension now and press the icon, you'll see that it will ask you what screen do you want to record and that's it. Next, we need to use the <code class="language-text">streamId</code> to get the screenshot.</p><h2 id="add-content-script">Add Content Script</h2><p>To obtain the stream from the <code class="language-text">streamId</code>, we need to use <a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia">getUserMedia</a>. However, this is not available in the service worker. So, we need to create a content script that receives a message from the service worker with the stream id, then gets the screenshot from the stream.</p><p>To add a content script, add the following to <code class="language-text">manifest.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"content_scripts"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"matches"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"<all_urls>"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"js"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"content_script.js"</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span></code></pre></div><p>Then, create <code class="language-text">content_script.js</code> in the root of the extension with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>runtime<span class="token punctuation">.</span>onMessage<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">message<span class="token punctuation">,</span> sender<span class="token punctuation">,</span> senderResponse</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>message<span class="token punctuation">.</span>name <span class="token operator">===</span> <span class="token string">'stream'</span> <span class="token operator">&&</span> message<span class="token punctuation">.</span>streamId<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This code listens for the "onMessage" event and checks if the <code class="language-text">message</code> received has a <code class="language-text">name</code> property that's equal to <code class="language-text">stream</code> and has a <code class="language-text">streamId</code> property, then we'll obtain the stream and take a screenshot of it.</p><p>Inside the if, we'll use <code class="language-text">getUserMedia</code> which returns a Promise that resolves to a <a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStream">MediaStream</a>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">let</span> track<span class="token punctuation">,</span> canvas navigator<span class="token punctuation">.</span>mediaDevices<span class="token punctuation">.</span><span class="token function">getUserMedia</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">video</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">mandatory</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">chromeMediaSource</span><span class="token operator">:</span> <span class="token string">'desktop'</span><span class="token punctuation">,</span> <span class="token literal-property property">chromeMediaSourceId</span><span class="token operator">:</span> message<span class="token punctuation">.</span>streamId <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">stream</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Notice that the parameter we passed to <code class="language-text">getUserMedia</code> takes an object of options. We're passing the <code class="language-text">chromeMediaSource</code> which equals to <code class="language-text">desktop</code>, and <code class="language-text">chromeMediaSourceId</code> which equals to the stream Id we received.</p><p>Next, inside the callback function for the resolved promise, we'll get the <a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack">MediaStreamTrack</a> and then capture a screenshot from it using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/ImageCapture">ImageCapture</a> API:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">track <span class="token operator">=</span> stream<span class="token punctuation">.</span><span class="token function">getVideoTracks</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token keyword">const</span> imageCapture <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ImageCapture</span><span class="token punctuation">(</span>track<span class="token punctuation">)</span> <span class="token keyword">return</span> imageCapture<span class="token punctuation">.</span><span class="token function">grabFrame</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre></div><p>In the end, we're returning the value of <code class="language-text">imageCapture.grabFrame</code> which returns a Promise that resolves to an ImageBitmap. Notice that we didn't use the <code class="language-text">takePhoto</code> method of the <code class="language-text">ImageCapture</code> API. The reason behind that is that there are known cases of a DOMException thrown using it and this is a <a href="https://github.com/GoogleChromeLabs/imagecapture-polyfill/issues/15">workaround</a> for it.</p><p>Next, we'll attach another <code class="language-text">then</code> method to handle the returned Promise from <code class="language-text">imageCapture.grabFrame</code>. The callback function will stop the stream, create a canvas and draw the ImageBitmap in it, then get the Data Url of the canvas:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">bitmap</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> track<span class="token punctuation">.</span><span class="token function">stop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> canvas <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'canvas'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> canvas<span class="token punctuation">.</span>width <span class="token operator">=</span> bitmap<span class="token punctuation">.</span>width<span class="token punctuation">;</span> canvas<span class="token punctuation">.</span>height <span class="token operator">=</span> bitmap<span class="token punctuation">.</span>height<span class="token punctuation">;</span> <span class="token keyword">let</span> context <span class="token operator">=</span> canvas<span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token string">'2d'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> context<span class="token punctuation">.</span><span class="token function">drawImage</span><span class="token punctuation">(</span>bitmap<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> bitmap<span class="token punctuation">.</span>width<span class="token punctuation">,</span> bitmap<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> canvas<span class="token punctuation">.</span><span class="token function">toDataURL</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Notice that it's important to set the width and height of the canvas to be equal to that of the <code class="language-text">bitmap</code>. If we don't, the canvas height and width will default to <code class="language-text">200px</code> and if the width or height of the bitmap is larger than that then the screenshot will be cropped.</p><p>In the end, we're returning <code class="language-text">canvas.toDataUrl</code>. We'll attach a last <code class="language-text">then</code> method that takes the URL returned as a parameter. This URL will be used to download the image on the user's device:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">url</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//TODO download the image from the URL</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Could not take screenshot"</span><span class="token punctuation">)</span> <span class="token function">senderResponse</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> err<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Notice that we also added <code class="language-text">catch</code> to catch any errors. As you can see in the <code class="language-text">catch</code> callback, we're calling the function <code class="language-text">senderResponse</code>. This function is the one we'll pass from the service worker or background script to the content script when sending the message.</p><p>At the end of the <code class="language-text">if</code> block we'll add the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span></code></pre></div><p>In a <code class="language-text">onMessage</code> event listener if the listener returns true that means that we'll later return a response to the sender using the callback function they passed when sending the message.</p><h2 id="download-screenshot">Download Screenshot</h2><p>To download the screenshot, we'll use the <a href="https://developer.chrome.com/docs/extensions/reference/downloads">Downloads</a> API. It provides a lot of methods to manage downloads like search, open, remove, and more.</p><p>Before we can use any of the methods, we need to add the <code class="language-text">downloads</code> permission to the <code class="language-text">permissions</code> array in <code class="language-text">manifest.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"permissions"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"desktopCapture"</span><span class="token punctuation">,</span> <span class="token string">"tabs"</span><span class="token punctuation">,</span> <span class="token string">"downloads"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div><p>Now, we can use the methods of the Downloads API. We'll use the method <code class="language-text">chrome.downloads.download</code> which takes an array of options as the first parameter and a callback function as the second.</p><p>However, this method cannot be called from the content script. We need to call it from the service worker/background script. So, when we get to the <code class="language-text">TODO</code> part in our code earlier, we need to send a message to the service worker with the URL we want to download. </p><p>To send a message in an extension, we use the <code class="language-text">chrome.runtime.sendMessage</code> which takes as a first parameter the message to send (which can be of any type), and an optional callback function as the second parameter, which is the function that the receiver of the message should call to deliver the response.</p><p>Add the following code in place of the <code class="language-text">TODO</code> comment:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">url</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> chrome<span class="token punctuation">.</span>runtime<span class="token punctuation">.</span><span class="token function">sendMessage</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'download'</span><span class="token punctuation">,</span> url<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>response<span class="token punctuation">.</span>success<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Screenshot saved"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Could not save screenshot"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> canvas<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token function">senderResponse</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Notice that we're sending the message <code class="language-text">{name: 'download', url}</code> to the receiver. As the message is sent to every listener in the extension, it's good to include a message property in the message you're sending to be able to handle different messages. We're also sending the URL to download the image from.</p><p>Let's go back to our service worker now. First, let's send a message to the content script from <code class="language-text">chooseDesktopMedia</code> callback function we earlier did:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token comment">//check whether the user canceled the request or not</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>streamId <span class="token operator">&&</span> streamId<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> chrome<span class="token punctuation">.</span>tabs<span class="token punctuation">.</span><span class="token function">sendMessage</span><span class="token punctuation">(</span>tab<span class="token punctuation">.</span>id<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">"stream"</span><span class="token punctuation">,</span> streamId<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">200</span><span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>Notice that to send a message to the content script we're using <code class="language-text">chrome.tabs.sendMessage</code>. The difference between this one and <code class="language-text">chrome.runtime.sendMessage</code> is that the former one sends the message to content scripts in a specific tab, whereas the first one sends the message to all scripts in the extension that listen to the <code class="language-text">onMessage</code> handler.</p><p>Next, we'll add a listener to the <code class="language-text">onMessage</code> event to receive the <code class="language-text">download</code> message and download the file to the user's machine:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>runtime<span class="token punctuation">.</span>onMessage<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">message<span class="token punctuation">,</span> sender<span class="token punctuation">,</span> senderResponse</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>message<span class="token punctuation">.</span>name <span class="token operator">===</span> <span class="token string">'download'</span> <span class="token operator">&&</span> message<span class="token punctuation">.</span>url<span class="token punctuation">)</span> <span class="token punctuation">{</span> chrome<span class="token punctuation">.</span>downloads<span class="token punctuation">.</span><span class="token function">download</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">filename</span><span class="token operator">:</span> <span class="token string">'screenshot.png'</span><span class="token punctuation">,</span> <span class="token literal-property property">url</span><span class="token operator">:</span> message<span class="token punctuation">.</span>url <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">downloadId</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">senderResponse</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>First, we're checking if the <code class="language-text">name</code> property of the message is equal to <code class="language-text">download</code> to make sure that the message received is the correct one. Then, we're downloading the file using <code class="language-text">chrome.downloads.download</code>, passing it the options object that has two options here: <code class="language-text">filename</code> which is the name of the file to download, and <code class="language-text">url</code> which is the URL to download. In the callback of the <code class="language-text">downloads</code> method we're calling the callback function passed by the sender.</p><p>Our extension is now ready. Go to <a href="chrome://extensions">chrome://extensions</a> again and reload the extension. Then, go to any page, click the icon of the extension. You'll be prompted to choose either the entire screen, a window, or a tab. Once you choose, a screenshot will be taken and saved on your machine.</p><hr><h2 id="conclusion">Conclusion</h2><p>In this tutorial, we learned how to a screenshot and a few of the concepts of a chrome extension shortly. If you want to learn more about Chrome extensions, make sure to check out the rest of my tutorials about <a href="https://blog.shahednasser.com/tag/browser-extensions">browser extensions</a>.</p></hr></hr>]]></content:encoded></item><item><title><![CDATA[How to Integrate MongoDB Realm with React: Part 2]]></title><description><![CDATA[In this tutorial, we'll see MongoDB's Realm user roles and data access restrictions in action.]]></description><link>https://blog.shahednasser.com/how-to-integrate-mongodb-realm-with-react-part-2/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ea8</guid><category><![CDATA[React]]></category><category><![CDATA[MongoDB]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 29 May 2021 19:42:41 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/a62e88450cff85b61373a1c069ce7cac/blog.shahednasser.com--1---1-.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/a62e88450cff85b61373a1c069ce7cac/blog.shahednasser.com--1---1-.png" alt="How to Integrate MongoDB Realm with React: Part 2"/><p><em>Please participate in <a href="https://yiro6gzu369.typeform.com/to/M2TFz504">this survey</a> to voice your opinion as a developer for an upcoming article!</em></p><p>In the first part of this tutorial, we went over how to set up a MongoDB Realm app with sample data, generate the schema, create and restrict roles, and then integrated it with a React app, implementing an authentication system.</p><p>In this tutorial, we'll go over how to ensure only logged-in users by email and password can add reviews, and we'll test adding reviews by users that are not logged in to see MongoDB Realm Roles and data access rules in action.</p><p>You can find the code for this tutorial <a href="https://github.com/shahednasser/mongodb-realm-tutorial">here</a>.</p><hr><h3 id="add-reviews-form">Add Reviews Form</h3><p>We'll start with the add reviews form. This form will be accessed through a link in the card of the restaurant that's showing on the home page. The restaurant ID will be passed as a URL parameter, then whatever review the user enters will be saved to that restaurant. At first, we'll allow all users to access the page to test the difference between the logged-in user and anonymous user, then we'll restrict access to the page to logged-in users only.</p><p>Create the component <code class="language-text">src/pages/AddReview.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">AddReview</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> AddReview</code></pre></div><p>Just like in the Authentication form, we'll use <code class="language-text">yup</code> for validation and <code class="language-text">formik</code> to make creating a form easier:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> reviewSchema <span class="token operator">=</span> yup<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">shape</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">review</span><span class="token operator">:</span> yup<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">required</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">function</span> <span class="token function">AddReview</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>loading<span class="token punctuation">,</span> setLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token keyword">function</span> <span class="token function">submitHandler</span> <span class="token punctuation">(</span><span class="token parameter">values</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//TODO add review </span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Formik initialValues<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">review</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> validationSchema<span class="token operator">=</span><span class="token punctuation">{</span>reviewSchema<span class="token punctuation">}</span> onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>submitHandler<span class="token punctuation">}</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>errors<span class="token punctuation">,</span> touched<span class="token punctuation">,</span> handleSubmit<span class="token punctuation">,</span> values<span class="token punctuation">,</span> handleChange<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>Form noValidate onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token punctuation">{</span>loading <span class="token operator">&&</span> <span class="token operator"><</span>Loading <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">}</span> <span class="token punctuation">{</span><span class="token operator">!</span>loading <span class="token operator">&&</span> <span class="token punctuation">(</span><span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span>Submit Review<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Row<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Review Score<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"number"</span> name<span class="token operator">=</span><span class="token string">"review"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>values<span class="token punctuation">.</span>review<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span>handleChange<span class="token punctuation">}</span> isValid<span class="token operator">=</span><span class="token punctuation">{</span>touched<span class="token punctuation">.</span>review <span class="token operator">&&</span> <span class="token operator">!</span>errors<span class="token punctuation">.</span>review<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control<span class="token punctuation">.</span>Feedback<span class="token operator">></span><span class="token punctuation">{</span>errors<span class="token punctuation">.</span>review<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Control<span class="token punctuation">.</span>Feedback<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Row<span class="token operator">></span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"text-center mt-2"</span><span class="token operator">></span> <span class="token operator"><</span>Button variant<span class="token operator">=</span><span class="token string">"primary"</span> type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span>Submit<span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Formik<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>We're just creating a form that has one number input for the review and for validation we're using the <code class="language-text">reviewSchema</code> which just checks that the review is filled and is a number.</p><p>Next, we need to add the logic of adding the review to the restaurant by the logged-in user. To do this, first, we need to pass the <code class="language-text">mongoContext</code> prop to the component which has the MongoDB <code class="language-text">client</code> and the Realm <code class="language-text">app</code> instances:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">AddReview</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span><span class="token literal-property property">mongoContext</span><span class="token operator">:</span> <span class="token punctuation">{</span>client<span class="token punctuation">,</span> app<span class="token punctuation">}</span><span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//...</span> <span class="token punctuation">}</span></code></pre></div><p>Next, we'll get the <code class="language-text">id</code> of the restaurant from the URL param using <a href="https://reactrouter.com/web/api/Hooks/useparams">useParam</a>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> id <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useParams</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre></div><p>And we'll get the <code class="language-text">history</code> instance to use later to redirect back to home page:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> history <span class="token operator">=</span> <span class="token function">useHistory</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre></div><p>We can now add the logic to update the <code class="language-text">restaurant</code> document of the passed <code class="language-text">id</code>, adding the user's <code class="language-text">grade</code>. To do that, we'll first get the <code class="language-text">restaurants</code> collection from our <code class="language-text">sample_restaurants</code> database:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">submitHandler</span><span class="token punctuation">(</span><span class="token parameter">values</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">const</span> rests <span class="token operator">=</span> client<span class="token punctuation">.</span><span class="token function">db</span><span class="token punctuation">(</span><span class="token string">'sample_restaurants'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">collection</span><span class="token punctuation">(</span><span class="token string">'restaurants'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>Next, we'll use the method <a href="https://docs.mongodb.com/realm/mongodb/update-documents/#update-a-single-document">updateOne</a> which takes a query to choose which document to update, then takes the changes. For us, the query will be the restaurant having the id that is passed as a URL param, and the change will be pushing a new entry into the <code class="language-text">grades</code> array inside the <code class="language-text">restaurant</code> document:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">rests<span class="token punctuation">.</span><span class="token function">updateOne</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string-property property">"_id"</span><span class="token operator">:</span> <span class="token constant">BSON</span><span class="token punctuation">.</span><span class="token function">ObjectID</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token string-property property">"$push"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token string-property property">"grades"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">score</span><span class="token operator">:</span> values<span class="token punctuation">.</span>review<span class="token punctuation">,</span> <span class="token literal-property property">user_id</span><span class="token operator">:</span> <span class="token constant">BSON</span><span class="token punctuation">.</span><span class="token function">ObjectID</span><span class="token punctuation">(</span>app<span class="token punctuation">.</span>currentUser<span class="token punctuation">.</span>id<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> history<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Notice that:</p><ol><li>To query the <code class="language-text">_id</code> field, we need to use <code class="language-text">BSON.ObjectID</code> to correctly pass the object id. Make sure to add at the beginning of the file <code class="language-text">import { BSON } from 'realm-web'</code>.</li><li>the <code class="language-text">grades</code> array holds objects that have <code class="language-text">date</code>, <code class="language-text">score</code>, and <code class="language-text">user_id</code>. This way, we're linking the grade to the appropriate user.</li><li><code class="language-text">updateOne</code> returns a promise, so once it resolves we're redirecting to the home page using <code class="language-text">history.push('/')</code>.</li></ol><p>And with that, our <code class="language-text">AddReview</code> component is ready. Next, we need to add the new page in our routes in <code class="language-text">src/App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Router<span class="token operator">></span> <span class="token operator"><</span>Navigation user<span class="token operator">=</span><span class="token punctuation">{</span>user<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>MongoContext<span class="token punctuation">.</span>Provider value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span>app<span class="token punctuation">,</span> client<span class="token punctuation">,</span> user<span class="token punctuation">,</span> setClient<span class="token punctuation">,</span> setUser<span class="token punctuation">,</span> setApp<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Container<span class="token operator">></span> <span class="token operator"><</span>Switch<span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/signup"</span> render<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">renderComponent</span><span class="token punctuation">(</span>Authentication<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'create'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/signin"</span> render<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">renderComponent</span><span class="token punctuation">(</span>Authentication<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/logout"</span> render<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">renderComponent</span><span class="token punctuation">(</span>LogOut<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/review/:id"</span> render<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">renderComponent</span><span class="token punctuation">(</span>AddReview<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/"</span> render<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">renderComponent</span><span class="token punctuation">(</span>Home<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Switch<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>MongoContext<span class="token punctuation">.</span>Provider<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Router<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Then, we'll need to add the link to the page inside each restaurant card. To do that, edit the <code class="language-text">src/components/RestaurantCard.js</code> component's return statement:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Card className<span class="token operator">=</span><span class="token string">"m-3"</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Body<span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Title<span class="token operator">></span><span class="token punctuation">{</span>restaurant<span class="token punctuation">.</span>name<span class="token punctuation">}</span> <span class="token operator"><</span>Badge variant<span class="token operator">=</span><span class="token string">"warning"</span><span class="token operator">></span><span class="token punctuation">{</span>avg<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>Badge<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>Card<span class="token punctuation">.</span>Title<span class="token operator">></span> <span class="token operator"><</span>Link to<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/review/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>restaurant<span class="token punctuation">.</span>_id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span> className<span class="token operator">=</span><span class="token string">"card-link"</span><span class="token operator">></span>Add Review<span class="token operator"><</span><span class="token operator">/</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token punctuation">.</span>Body<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token operator">></span> <span class="token punctuation">)</span></code></pre></div><p>Notice that we're passing the restaurant id to the link as a parameter.</p><p>Let's run the server now:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>Make sure to log in if you aren't already. We'll test how this will work as a guest in a bit.</p><p>You should be able to see new links for each restaurant on the home page now.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-05-29-at-7.28.50-PM.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 2" loading="lazy"/></figure><p>Click on "Add Review" for any of the restaurants. You'll see a number input field, enter any number and click "Submit". If you're logged in, you should see a loader, then you'll be redirected to the home page. You can see that the restaurant's review has changed.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/React-App.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 2" loading="lazy"/></figure><h3 id="test-mongodb-realm-authorization-roles">Test MongoDB Realm Authorization Roles</h3><p>If you recall from <a href="https://blog.shahednasser.com/how-to-integrate-mongo-realm-with-react-part-1/#setup-authentication-in-realm-app">part 1</a>, we added a new User role. This user role allows users that have an email to insert or update only the <code class="language-text">grades</code> field of a restaurant. For a user to "belong" to the User role they need to have an email, which we declared in the "Apply When" field:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"%%user.data.email"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"%exists"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>So, an anonymous user does not have permission to make any changes to the <code class="language-text">grades</code> field or any field of the <code class="language-text">restaurants</code> collection.</p><p>Let's test that. Log out from the current user. You should still be able to see the Add Review link and be able to access the page, as we still haven't added conditions for a user's authentication.</p><p>Try to add a review to any restaurant. Since you're not logged in, you'll get an alert with an error and nothing will be added.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-05-29-at-7.43.09-PM.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 2" loading="lazy"/></figure><p>As you can see the error says "update not permitted". The user does not belong to the "User" role we created, so they're not allowed to add a review.</p><p>Let's now hide the link to "Add Review" for anonymous users in <code class="language-text">src/components/RestaurantCard.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><span class="token operator">!</span><span class="token function">isAnon</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token operator"><</span>Link to<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/review/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>restaurant<span class="token punctuation">.</span>_id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span> className<span class="token operator">=</span><span class="token string">"card-link"</span><span class="token operator">></span>Add Review<span class="token operator"><</span><span class="token operator">/</span>Link<span class="token operator">></span><span class="token punctuation">}</span></code></pre></div><p>Add <code class="language-text">user</code> to the list of props for <code class="language-text">RestaurantCard</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">RestaurantCard</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>restaurant<span class="token punctuation">,</span> user<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//...</span> <span class="token punctuation">}</span></code></pre></div><p>Pass the <code class="language-text">user</code> prop to <code class="language-text">RestaurantCard</code> in <code class="language-text">src/pages/Home.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>RestaurantCard key<span class="token operator">=</span><span class="token punctuation">{</span>restaurant<span class="token punctuation">.</span>_id<span class="token punctuation">}</span> restaurant<span class="token operator">=</span><span class="token punctuation">{</span>restaurant<span class="token punctuation">}</span> user<span class="token operator">=</span><span class="token punctuation">{</span>user<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>And let's add a condition in <code class="language-text">src/pages/AddReview.js</code> to redirect to home page if the user is not logged in:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">AddReview</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span><span class="token literal-property property">mongoContext</span><span class="token operator">:</span> <span class="token punctuation">{</span>client<span class="token punctuation">,</span> app<span class="token punctuation">,</span> user<span class="token punctuation">}</span><span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>loading<span class="token punctuation">,</span> setLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> id <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useParams</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> history <span class="token operator">=</span> <span class="token function">useHistory</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isAnon</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> history<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">//...</span> <span class="token punctuation">}</span></code></pre></div><p>Now, if you're not logged in you will not be able to see the review and if you try to access the reviews page directly you'll be redirected to the home page.</p><p>Let's test another aspect of the role we created. As we said, the role we created allows logged-in users to update the <code class="language-text">grades</code> field. However, they should not be able to edit any other field.</p><p>Let's change the parameter for <code class="language-text">updateOne</code> in <code class="language-text">AddReview</code> to change the name instead:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">rests<span class="token punctuation">.</span><span class="token function">updateOne</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string-property property">"_id"</span><span class="token operator">:</span> <span class="token constant">BSON</span><span class="token punctuation">.</span><span class="token function">ObjectID</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"test"</span><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>This is just to easily test this restriction. Now, login and go to the "Add Review" and click Submit. You'll see the same "update not permitted" message as before.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-05-29-at-7.51.59-PM.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 2" loading="lazy"/></figure><p>This shows how we can easily manage our users, their roles, and data access through MongoDB Realm.</p><hr><h3 id="conclusion">Conclusion</h3><p>Using MongoDB Realm allows us to easily create serverless apps while also managing data access, roles, and authentication. It's also available to be used on the web (like in this tutorial), on mobile apps, and more. In this tutorial, we covered the basics that you'll probably need in most use cases. If you dive deeper into it, you'll surely find even more features that will be helpful for your serverless apps.</p></hr></hr>]]></content:encoded></item><item><title><![CDATA[How to Easily Style Magento 2 Emails]]></title><description><![CDATA[Learn how to easily style your emails in Magento 2]]></description><link>https://blog.shahednasser.com/how-to-easily-style-magento-2-emails/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ea7</guid><category><![CDATA[Magento]]></category><category><![CDATA[PHP]]></category><category><![CDATA[Beginners]]></category><category><![CDATA[CSS]]></category><category><![CDATA[Design]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 27 May 2021 19:56:24 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/eb195780a13d8f6b32692d64d8a01d4c/photo-1603539279542-e7cf76a92801.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/eb195780a13d8f6b32692d64d8a01d4c/photo-1603539279542-e7cf76a92801.jpg" alt="How to Easily Style Magento 2 Emails"/><p>Understanding Magento 2 themes can be hard. The structure of the files, especially the <code class="language-text">less</code> files can get confusing. One of the hard things to understand is how to style your emails.</p><p>In this tutorial, we'll cover how we can easily style emails in Magento 2.</p><hr><h3 id="prerequisites-create-a-theme">Prerequisites: Create a Theme </h3><p>If you don't already have a theme created, we'll go over the steps quickly. If you have a theme you can skip this. Keep in mind we're not actually going to explain everything about creating a theme here, as this can be long.</p><p>First, create the directories <code class="language-text">app/design/VENDER/THEME_NAME</code> where <code class="language-text">VENDOR</code> is usually substituted with the company or owner's name, and <code class="language-text">THEME_NAME</code> is the name of the them.</p><p>Next, inside <code class="language-text">THEME_NAME</code>, create <code class="language-text">theme.xml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>theme</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:framework:Config/etc/theme.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>THEME_NAME<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>parent</span><span class="token punctuation">></span></span>Magento/blank<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>parent</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>theme</span><span class="token punctuation">></span></span> </code></pre></div><p>Replace <code class="language-text">THEME_NAME</code> with the name of your theme.</p><p>Create <code class="language-text">registration.php</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token comment">/** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */</span> <span class="token keyword">use</span> <span class="token package">Magento<span class="token punctuation">\</span>Framework<span class="token punctuation">\</span>Component<span class="token punctuation">\</span>ComponentRegistrar</span><span class="token punctuation">;</span> <span class="token class-name static-context">ComponentRegistrar</span><span class="token operator">::</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token class-name static-context">ComponentRegistrar</span><span class="token operator">::</span><span class="token constant">THEME</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'frontend/VENDOR/THEME_NAME'</span><span class="token punctuation">,</span> <span class="token constant">__DIR__</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><p>Replace <code class="language-text">VENDOR</code> and <code class="language-text">THEME_NAME</code> with your own.</p><p>Create <code class="language-text">composer.json</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"VENDOR/THEME_NAME"</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"N/A"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"magento2-theme"</span><span class="token punctuation">,</span> <span class="token property">"license"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"OSL-3.0"</span><span class="token punctuation">,</span> <span class="token string">"AFL-3.0"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"config"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"sort-packages"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"version"</span><span class="token operator">:</span> <span class="token string">"100.4.2"</span><span class="token punctuation">,</span> <span class="token property">"require"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"php"</span><span class="token operator">:</span> <span class="token string">"~7.3.0||~7.4.0"</span><span class="token punctuation">,</span> <span class="token property">"magento/framework"</span><span class="token operator">:</span> <span class="token string">"103.0.*"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"autoload"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"files"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"registration.php"</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>Replace <code class="language-text">VENDOR</code> and <code class="language-text">THEME_NAME</code> with your own.</p><p>Create <code class="language-text">etc/view.xml</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token prolog"><?xml version="1.0"?></span> <span class="token comment"><!-- /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>view</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>noNamespaceSchemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:magento:framework:Config/etc/view.xsd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>media</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>images</span> <span class="token attr-name">module</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento_Catalog<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>bundled_product_customization_page<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumbnail<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>140<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>140<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>cart_cross_sell_products<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>240<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>300<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>cart_page_product_thumbnail<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>110<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>160<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>category_page_grid<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>240<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>300<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>category_page_list<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>240<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>300<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>customer_account_my_tags_tag_view<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>100<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>100<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>customer_account_product_review_page<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>285<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>285<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>customer_shared_wishlist<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>113<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>113<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>gift_messages_checkout_small_image<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>75<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>75<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>gift_messages_checkout_thumbnail<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumbnail<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>100<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>100<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mini_cart_product_thumbnail<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumbnail<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>156<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>156<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>new_products_content_widget_grid<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>240<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>300<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>new_products_content_widget_list<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>270<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>270<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>new_products_images_only_widget<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>78<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>78<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_base_image<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>265<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>265<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_comparison_list<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>140<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>140<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_page_image_large<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_page_image_medium<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>700<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>700<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_page_image_small<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumbnail<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>90<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>90<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_swatch_image_large<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_swatch_image_medium<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>240<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>300<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_swatch_image_small<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumbnail<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>88<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>110<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_page_main_image<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>700<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>700<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_page_main_image_default<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>700<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>700<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_page_more_views<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumbnail<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>90<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>90<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_stock_alert_email_product_image<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>76<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>76<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_small_image<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>135<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>135<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_thumbnail_image<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumbnail<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>75<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>75<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>recently_compared_products_grid_content_widget<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>240<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>300<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>recently_compared_products_images_names_widget<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumbnail<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>75<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>90<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>recently_compared_products_images_only_widget<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumbnail<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>76<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>76<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>recently_compared_products_list_content_widget<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>270<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>207<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>recently_viewed_products_grid_content_widget<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>240<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>300<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>recently_viewed_products_images_names_widget<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>75<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>90<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>recently_viewed_products_images_only_widget<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>76<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>76<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>recently_viewed_products_list_content_widget<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>270<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>270<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>related_products_list<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>140<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>140<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>review_page_product_image<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>285<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>285<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>rss_thumbnail<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumbnail<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>75<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>75<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sendfriend_small_image<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>75<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>75<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>shared_wishlist_email<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>135<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>135<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>side_column_widget_product_thumbnail<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumbnail<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>75<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>90<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>upsell_products_list<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>140<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>140<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>wishlist_sidebar_block<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumbnail<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>75<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>90<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>wishlist_small_image<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>113<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>113<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>image</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>wishlist_thumbnail<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>small_image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>width</span><span class="token punctuation">></span></span>240<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>width</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>height</span><span class="token punctuation">></span></span>300<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>height</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>image</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>images</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>media</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>vars</span> <span class="token attr-name">module</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento_Catalog<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token comment"><!-- Gallery and magnifier theme settings. Start --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>gallery<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>nav<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>thumbs<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Gallery navigation style (false/thumbs/dots) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>loop<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Gallery navigation loop (true/false) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keyboard<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Turn on/off keyboard arrows navigation (true/false) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>arrows<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Turn on/off arrows on the sides preview (true/false) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>caption<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>false<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Display alt text as image title (true/false) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>allowfullscreen<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Turn on/off fullscreen (true/false) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>navdir<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>horizontal<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Sliding direction of thumbnails (horizontal/vertical) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>navarrows<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Turn on/off on the thumbs navigation sides arrows(true/false) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>navtype<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>slides<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Sliding type of thumbnails (slides/thumbs) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>transition<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>effect<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>slide<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Sets transition effect for slides changing (slide/crossfade/dissolve) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>duration<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>500<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Sets transition duration in ms --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>fullscreen<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>nav<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>thumbs<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Fullscreen navigation style (false/thumbs/dots) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>loop<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Fullscreen navigation loop (true/false/null) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>arrows<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>false<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Turn on/off arrows on the sides preview in fullscreen (true/false/null) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>caption<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>false<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Display alt text as image title in fullscreen(true/false) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>navdir<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>horizontal<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!--Sliding direction of thumbnails in fullscreen(horizontal/vertical) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>navtype<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>slides<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Sliding type of thumbnails (slides/thumbs) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>transition<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>effect<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>dissolve<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Sets transition effect for slides changing (slide/crossfade/dissolve) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>duration<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>500<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Sets transition duration in ms --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>magnifier<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>fullscreenzoom<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>20<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Zoom for fullscreen (integer)--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>top<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Top position of magnifier --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>left<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Left position of magnifier --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Width of magnifier block --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>height<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Height of magnifier block --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>eventType<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>hover<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Action that atcivates zoom (hover/click) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>enabled<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>false<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Turn on/off magnifier (true/false) --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>breakpoints<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mobile<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>conditions<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>max-width<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>767px<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>options<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>options<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>nav<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>dots<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- end. Gallery and magnifier theme settings --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_small_image_sidebar_size<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>100<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Override for small product image --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_base_image_size<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>275<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Override for base product image --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_base_image_icon_size<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>48<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Base product image icon size --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_list_image_size<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>166<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- New Product image size used in product list --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_zoom_image_size<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>370<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- New Product image size used for zooming --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_image_white_borders<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>vars</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>vars</span> <span class="token attr-name">module</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Magento_Bundle<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>product_summary_image_size<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>58<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token comment"><!-- New Product image size used for summary block--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>vars</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>vars</span> <span class="token attr-name">module</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Js_Bundle<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>var</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>bundle_size<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>1MB<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>var</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>vars</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>exclude</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::chartjs/Chart.min.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::jquery/jquery.min.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::jquery/jquery-ui-1.9.2.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::jquery/jquery.details.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::jquery/jquery.hoverIntent.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::jquery/colorpicker/js/colorpicker.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::requirejs/require.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::requirejs/text.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::legacy-build.min.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::mage/captcha.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::mage/dropdown_old.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::mage/list.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::mage/loader_old.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::mage/webapi.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::mage/zoom.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::mage/translate-inline-vde.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::mage/requirejs/mixins.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::mage/requirejs/static.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Customer::js/zxcvbn.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Catalog::js/zoom.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Ui::js/lib/step-wizard.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Ui::js/form/element/ui-select.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Ui::js/form/element/file-uploader.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Ui::js/form/components/insert.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Ui::js/form/components/insert-listing.js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Ui::js/timeline<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Ui::js/grid<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Ui::js/dynamic-rows<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Ui::templates/timeline<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Ui::templates/grid<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Ui::templates/dynamic-rows<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Swagger::swagger-ui<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Magento_Tinymce3::tiny_mce<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::modernizr<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::tiny_mce<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::varien<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::jquery/editableMultiselect<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::jquery/jstree<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::jquery/fileUploader<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::css<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::lib<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::extjs<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::prototype<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::scriptaculous<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::less<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::mage/adminhtml<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>item</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>directory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Lib::mage/backend<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>item</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>exclude</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>view</span><span class="token punctuation">></span></span> </code></pre></div><p>That's all you need to create a theme. Now go to your Magento admin and log in. Then, go to Content -> Configuration. Click on Edit for the Default Store View. Now, choose your theme from the "Applied Theme" dropdown and click Save Configuration.</p><hr><h3 id="understanding-the-base-email-styling-files">Understanding the Base Email Styling Files</h3><p>Usually, all custom themes (like the one we just created) extend Magento's basic theme <code class="language-text">blank</code>. So, the styling in that theme will be applied. </p><p>The code for <code class="language-text">blank</code> is inside <code class="language-text">vendor/magento/theme-frontend-blank</code>. All theme stylings are in <code class="language-text">web/css</code>.</p><p>Inside <code class="language-text">blank</code>'s theme stylings, we'll focus on 3 files:</p><ol><li><code class="language-text">web/css/source/_email-base.less</code>: The file that holds the email stylings.</li><li><code class="language-text">web/css/source/_email-extend.less</code>: This file allows child themes to extend the default stylings in <code class="language-text">_email-base.less</code> and make any necessary changes needed.</li><li><code class="language-text">web/css/source/_email-variables.less</code>: This file allows child themes to modify variables used in <code class="language-text">_email-base.less</code>.</li></ol><p>The most important one here is <code class="language-text">email-variables.less</code>. We can easily modify the styles of emails just by changing the values of some variables. You can find these variables used in <code class="language-text">_email-base.less</code> like:</p><ol><li><code class="language-text">@font-family__base</code>: The font family to use.</li><li><code class="language-text">@email__background-color</code>: The entire background color for the email</li><li><code class="language-text">@email-content__background-color</code>: The background color for the main content of the email. This is helpful if you want the content of the email to not span the entire document's width.</li><li><code class="language-text">@email-body__width</code>: specify the width of the content of the email.</li></ol><p>There are many other variables as well that you can use to modify emails. I suggest you take a look at <code class="language-text">web/css/source/_email-base.less</code> to see all the variables that can be used.</p><p>By default, the emails will have a pure background color, with the content's width being <code class="language-text">600px</code>. It should look something like this:</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-05-26-at-8.24.55-PM.png" class="kg-image" alt="How to Easily Style Magento 2 Emails" loading="lazy"/></figure><p>Let's say we want to make the background color of the body <code class="language-text">#8ba9b7</code>, and make the width of the content <code class="language-text">70%</code>.</p><p>To do that, create the file <code class="language-text">app/design/frontend/VENDOR_NAME/THEME_NAME/web/css/source/_email-variables.less</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="less"><pre class="language-less"><code class="language-less"><span class="token variable">@email__background-color<span class="token punctuation">:</span></span> #8ba9b7<span class="token punctuation">;</span> <span class="token variable">@email-body__width<span class="token punctuation">:</span></span> 70%<span class="token punctuation">;</span></code></pre></div><p>That's all we need to do to customize the email styling! Run the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">bin/magento setup:static-content:deploy -f</code></pre></div><p>or if you're using Grunt, run the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">grunt refresh</code></pre></div><p><em>Recommended Read: <a href="https://blog.shahednasser.com/how-to-make-your-front-end-development-faster-in-magento-2-using-grunt/">How to Make Your Front-End Development Faster in Magento 2 Using Grunt</a>.</em></p><p>Emails now will look like this:</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-05-26-at-8.38.56-PM.png" class="kg-image" alt="How to Easily Style Magento 2 Emails" loading="lazy"/></figure><p>Next step, we'll center the footer text and change the text color to white.</p><p>All changes to the design that's not just changing the variables' values should be put inside <code class="language-text">web/css/source/_email-extend.less</code>. So, create the file <code class="language-text">app/design/frontend/VENDOR/THEME_NAME/web/css/source/_email-extend.less</code>.</p><p>The footer has the <code class="language-text">footer</code> class, so we'll reference it through the selector <code class="language-text">.footer</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="less"><pre class="language-less"><code class="language-less"><span class="token selector">.footer</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span> <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>To see the changes, compile the code as mentioned earlier. </p><p>The email will now look like this:</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-05-26-at-8.45.13-PM.png" class="kg-image" alt="How to Easily Style Magento 2 Emails" loading="lazy"/></figure><hr><h3 id="using-fonts-in-emails">Using Fonts in Emails</h3><p>Using fonts in emails is tricky. We'll go over how to use one of the <a href="https://knowledgebase.constantcontact.com/articles/knowledgebase/5877-web-safe-font-selections-in-campaign-emails?lang=en_US">Web Safe Fonts</a>, as those should work on most clients. We'll be using Verdana.</p><p>To change the font, set the variable <code class="language-text">@font-family__base</code> in <code class="language-text">_email-variables.less</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="less"><pre class="language-less"><code class="language-less"><span class="token variable">@font-family__base<span class="token punctuation">:</span></span> <span class="token string">'Verdana'</span><span class="token punctuation">,</span> sans<span class="token operator">-</span>serif<span class="token punctuation">;</span></code></pre></div><p>If we compile as usual and test the email, we can see that the font has changed:</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-05-27-at-10.41.49-PM.png" class="kg-image" alt="How to Easily Style Magento 2 Emails" loading="lazy"/></figure><p>You can also use your own fonts, however, this rarely works in most email clients.</p><p><strong>Use Own Fonts</strong></p><p>To use your own font, first, copy the font to <code class="language-text">app/design/frontend/VENDOR/THEME_NAME/web/font/FONT</code> where <code class="language-text">FONT</code> is the font file. For example, <code class="language-text">Opensans.ttf</code>.</p><p>Next, in <code class="language-text">_email-extend.less</code>, we use the <code class="language-text">.lib-font-face</code> mixin which receives the following parameters:</p><ol><li><code class="language-text">@family-name</code>: the font family name.</li><li><code class="language-text">@font-path</code>: the path to the font family.</li><li><code class="language-text">@font-weight</code>: the weight of the font</li><li><code class="language-text">@font-style</code>: the style of the font</li><li><code class="language-text">@font-display</code>: display property of the font</li><li><code class="language-text">@font-format</code>: the extension type of the font. This is optional. If your <code class="language-text">FONT</code>'s extension is <code class="language-text">woff</code> you don't need to pass this.</li><li><code class="language-text">@font-type</code>: same as <code class="language-text">@font-format</code>. When using a font format that's different than <code class="language-text">woff</code> you need to pass both parameters.</li></ol><p>So, this is an example of how you'll use the mixin:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="less"><pre class="language-less"><code class="language-less">.<span class="token function">lib-font-face</span><span class="token punctuation">(</span> <span class="token atrule">@family-name<span class="token punctuation">:</span> 'MyFont', @font-path<span class="token punctuation">:</span> '@</span><span class="token punctuation">{</span>baseDir<span class="token punctuation">}</span>fonts<span class="token operator">/</span>FONT'<span class="token punctuation">,</span> <span class="token variable">@font-weight<span class="token punctuation">:</span></span> 300<span class="token punctuation">,</span> <span class="token variable">@font-style<span class="token punctuation">:</span></span> normal<span class="token punctuation">,</span> <span class="token variable">@font-display<span class="token punctuation">:</span></span> swap<span class="token punctuation">,</span> <span class="token variable">@font-format<span class="token punctuation">:</span></span> <span class="token string">'ttf'</span><span class="token punctuation">,</span> <span class="token variable">@font-type<span class="token punctuation">:</span></span> <span class="token string">'ttf'</span> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Notice that for <code class="language-text">@font-path</code> we're using the variable <code class="language-text">baseDir</code> which refers to <code class="language-text">app/design/frontend/VENDOR/THEME_NAME/web</code>.</p><p>Then, in <code class="language-text">email-variables.less</code> set the <code class="language-text">@font-family__base</code> to your font:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="less"><pre class="language-less"><code class="language-less"><span class="token variable">@font-family__base<span class="token punctuation">:</span></span> <span class="token string">'MyFont'</span><span class="token punctuation">,</span> sans<span class="token operator">-</span>serif<span class="token punctuation">;</span></code></pre></div><p>Then compile the changes and test the email, however, there's no guarantee that it will actually work.</p><p><strong>Note About Using Google Fonts</strong></p><p>If you want to use <a href="https://fonts.google.com/">Google Fonts</a>, which again is not guaranteed to work, here's a little tip on the best way to do it.</p><p>First, choose a font. For example, <a href="https://fonts.google.com/specimen/Odibee+Sans">Odibee Sans</a>. Choose the style you want, then copy the import link.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Odibee-Sans-Google-Fonts.png" class="kg-image" alt="How to Easily Style Magento 2 Emails" loading="lazy"/></figure><p>Open that link your browser, it will give you the CSS rules to create the font.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-05-27-at-10.53.41-PM.png" class="kg-image" alt="How to Easily Style Magento 2 Emails" loading="lazy"/></figure><p>Copy it, then paste it in <code class="language-text">email-extend.less</code>. Then, change the value for the <code class="language-text">@font-family_base</code> variable in <code class="language-text">_email-variables.less</code> to the font:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="less"><pre class="language-less"><code class="language-less"><span class="token variable">@font-family__base<span class="token punctuation">:</span></span> <span class="token string">'Odibee Sans'</span><span class="token punctuation">,</span> sans<span class="token operator">-</span>serif<span class="token punctuation">;</span></code></pre></div><p>After compiling the changes as before, you can test the email and see if the font works. However, as stated earlier, this is not supported by most clients and most probably will not work. It's best to stick to websafe fonts.</p></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Why Facebook Deserves To Be Dropped For Once And For All]]></title><description><![CDATA[Facebook has yet to show that it actually cares about its users]]></description><link>https://blog.shahednasser.com/why-facebook-deserves-to-be-dropped-for-once-and-all/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ea6</guid><category><![CDATA[My Experience]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 24 May 2021 19:33:07 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/f2f7eca3c0ccf83d0e1beb30c230400b/IMG_4797.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/f2f7eca3c0ccf83d0e1beb30c230400b/IMG_4797.jpg" alt="Why Facebook Deserves To Be Dropped For Once And For All"/><p>In May 2021 Facebook's rating keeps dropping reaching 1.7 stars on the App Store and 2.4 on the Google Play Store (at the time of writing this article). Facebook even requested from the App Store to remove the negative reviews, <a href="https://www.businessinsider.com/apple-refused-request-remove-negative-ratings-for-facebook-app-2021-5">but Apple refused their request</a>.</p><p>This is not the first time Facebook has been under heat, and most probably won't be the last time. Over the years, Facebook kept disappointing its users with problems ranging from security issues to profiting from user's data to now constricting their user's opinions and allowing only the views they believe are correct.</p><p>When you look at everything that happened with Facebook throughout the past few years, you'll realize how surprising it still has users to begin with.</p><p>We won't go over every single scandal Facebook had, but there are some that not only strongly affect Facebook's image as a leading tech company, but also harm their relationship with their users.</p><p>In 2018, It was revealed that Facebook basically <a href="https://www.theatlantic.com/technology/archive/2018/12/facebooks-failures-and-also-its-problems-leaking-data/578599/">gave away user's data</a> without their knowledge or permission. Of course, we all remember this scandal and what happened, and how much it damaged Facebook's image at the time. Facebook sacrificed their user's data, which they trusted them with, for their own benefit and for political reasons. </p><p>In 2019 it was revealed that for many years Facebook stored the user's password in <a href="https://www.independent.co.uk/life-style/gadgets-and-tech/news/facebook-passwords-plain-text-instagram-admission-a8833941.html#:~:text=Facebook%20stored%20hundreds%20of%20millions,its%20internal%20data%20storage%20systems.">plain text files</a>. Even though Facebook says there was no evidence of these passwords being abused, it still doesn't change the fact that these passwords were visible to thousands of their employees. Facebook clearly didn't value the user's security or privacy.</p><p>In May 2021, Facebook yet again was under fire as users were noticing that they had no freedom of speech on the platform anymore. When freely stating their opinions that are Pro-Palestine, they noticed that their posts were being removed or reported as harmful or dangerous. This backfired at Facebook, as users resorted to another way of freely voicing their opinion by giving the app bad reviews that made its rating drop tremendously. </p><p>As more time passes by, Facebook seems to be insistent on making sure every last one of its users loses their trust in it. By signing up to Facebook you're highly likely signing up for your data being abused and breached by the platform itself, for poor security and almost no privacy, and for your voice to be silenced unless it matches the platform's own opinion and beliefs. </p><p>There's no denying that Facebook was one of the very first social media platforms that changed the game and how people perceived social media. It played a big role in making social media what it is today. However, it seems that its role has been diminished and changed into what's politically best for the company. It's no longer interested in what the users want, it's only interested in how to use these users to make money and fight for their own agenda.</p><p>While companies like <a href="https://www.highlandernews.org/82516/apples-stronger-stance-for-user-privacy-works-to-the-advantage-of-their-consumers/">Apple</a>, <a href="https://www.thedrum.com/news/2021/05/17/duckduckgo-firefox-github-say-no-flocing-way-google-s-privacy-updates">DuckDuckGo</a>, <a href="https://techcrunch.com/2021/02/24/mozilla-beefs-up-anti-cross-site-tracking-as-chrome-still-lags-on-privacy/">Mozilla</a>, and others are working hard to maintain user's privacy, it's a shame we still have companies like Facebook <a href="https://www.cnet.com/news/apples-privacy-battle-with-facebook-just-became-all-out-war/">who are fighting against that</a>. It's a shame, but it's not surprising at all coming from Facebook, as it has yet to show that it actually cares about its users.</p><p>To still be waiting for that after 17 years since its launch, I think it's hopeless. There's no point in waiting for the platform to start respecting its users and valuing them. I think it's time to label Facebook as "Use at your own risk." </p>]]></content:encoded></item><item><title><![CDATA[How to Integrate MongoDB Realm with React: Part 1]]></title><description><![CDATA[In this tutorial, we'll learn how to create a MongoDB Realm application and integrate it with React]]></description><link>https://blog.shahednasser.com/how-to-integrate-mongo-realm-with-react-part-1/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ea5</guid><category><![CDATA[MongoDB]]></category><category><![CDATA[React]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 22 May 2021 16:17:41 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/450da8e7b6663466e826ac11168c7984/blog.shahednasser.com-min.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/450da8e7b6663466e826ac11168c7984/blog.shahednasser.com-min.png" alt="How to Integrate MongoDB Realm with React: Part 1"/><p>You can read part 2 <a href="https://blog.shahednasser.com/how-to-integrate-mongodb-realm-with-react-part-2/">here</a>.</p><p>MongoDB Realm is a serverless backend that allows you to not only write and read data easily but also provides easy ways to authenticate users, keep your data synchronized across multiple devices, and more.</p><p>In this tutorial, we'll learn how to create a MongoDB Realm application, add sample data to it, restrict data access based on user roles, then how to integrate the application with React. We'll create a website that shows restaurant reviews and allows users to create an account and add their own reviews.</p><p>You can find the code for this tutorial <a href="https://github.com/shahednasser/mongodb-realm-tutorial">here</a>.</p><hr><h3 id="create-a-mongodb-realm-app">Create a MongoDB Realm App</h3><p><strong>Create a MongoDB Cluster</strong></p><p>Before we can create a MongoDB Realm App, we need to create a MongoDB Cluster. To do that, go to the <a href="https://cloud.mongodb.com/">Atlas portal</a>. If you don't have an account or you're not already logged in, you need to do that first.</p><p>If you're not redirected to the Projects page, click on the logo at the top left.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Projects-Cloud-MongoDB-Cloud.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>Once you're on the Projects page, click on the New Project button at the right.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Projects-Cloud-MongoDB-Cloud2.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>Then you will be asked to enter a project name. You can name it whatever you want. After that, you'll be asked to add members, if you need to. Once done, click on Create Project.</p><p>Once the project is created, you will be redirected to the Clusters page. Click on "Build a Cluster"</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Clusters-Atlas-MongoDB-Atlas.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>You'll be asked to pick a cluster plan. For this tutorial, you can just choose the free plan.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Choose-a-Path-Atlas-MongoDB-Atlas.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>Then after that you can just click on "Create Cluster"</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Create-Cluster-Atlas-MongoDB-Atlas.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>After this, your cluster will take some time to deploy. You need to wait until it's created and deploy, which can take a couple of minutes.</p><p>The next step will be to add a sample dataset to our Cluster. If you already have a dataset, you can add your own data instead.</p><p>To start adding data, click on Collections in the Cluster you created.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Clusters-Atlas-MongoDB-Atlas2.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>Then, click on Load a Sample Dataset.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Data-Atlas-MongoDB-Atlas.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>A popup window will open to ask for confirmation. Once you confirm, a sample dataset will be installed in your cluster. This dataset contains a bunch of useful databases and collections for different use cases. </p><p>It will take a minute or two to finish installing the sample dataset. Once it's done, you'll see that now you have a few databases now.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Data-Atlas-MongoDB-Atlas2.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>We'll only be using the <code class="language-text">sample_restaurants</code> database, so you can go ahead and delete the rest by clicking on the trash icon that appears when you hover a database name.</p><p>Now that our MongoDB Cluster is ready, let's go ahead and create a MongoDB Realm App.</p><p><strong>Create a MongoDB Realm App</strong></p><p>To go to MongoDB Realm, click on "Realm" in the tab bar next to "Atlas"</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Clusters-Atlas-MongoDB-Atlas3.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>A dialog will show to start creating MongoDB Realm App. You'll need to enter a name for the Realm Application which can be whatever you want. Then, you'll need to choose a cluster to link the Realm App to. You'll need to choose the cluster we just created. Once you do that, click on Create Realm Application.</p><p>Next, we'll need to choose a collection from the cluster to add access to from the Realm app. To do that, click on Get Started under Add a Collection on the dashboard.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Dashboard-MongoDB-Realm.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>You'll have to pick the database, which is <code class="language-text">sample_restaurants</code>. Then choose a collection, which will be <code class="language-text">restaurants</code>. </p><p>Next, we need to select a permission template. Permission templates allow to easily restrict read and write access as necessary. </p><p>In the website we're creating, all users can read all data about restaurants, and they can write reviews in their own account. </p><p>For now, we'll just choose "Users can only read all data" from the dropdown. Once you're done, click "Add Collection." Next, click on <code class="language-text">neighborhoods</code> from the sidebar and choose the same template then Add Collection.</p><p>Every time you make changes to the Realm App, you have to deploy it for changes to take effect. To deploy the changes we just made, click on "Review Draft & Deploy" in the blue banner at the top.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Data-Sources-MongoDB-Realm.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>And that's it! We created a Realm App that's linked to our cluster and the collections in it. This will provide a serverless backend that allows us to retrieve and write data to our cluster easily.</p><hr><h2 id="generate-schemas">Generate Schemas</h2><p>To be able to query our collections and documents, and to be able to apply certain roles, permissions and restrictions, we need to generate Schema definitions for each of the collections. To do that, click on Schema in the sidebar.</p><p>Then, click on Generate Schema button. This will generate the schema based on the data that's already in the collection. </p><p>Under "Generate schema(s) for:" choose "all unconfigured collections" and for Sample type in "20" as we don't need to sample so many documents considering our data is simple. Then, click on Generate Schema.</p><p>Once it's done, you'll see the Schema generated with all the fields and their respective types.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Data-Sources-MongoDB-Realm3.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><hr><h2 id="setup-authentication-in-realm-app">Setup Authentication in Realm App</h2><p>In our Realm app, we'll be using two Authentication providers:</p><ol><li>Anonymous Login: Allow the user to view all data without actually having to login.</li><li>Email & Password Login: Users have to login with email and password to write their reviews.</li></ol><p>This means that users have permission to read all data, but only write their own data.</p><p>In the Realm Portal, click on Authentication in the sidebar. You'll see a few Authentication providers that are all disabled. </p><p>We'll first enable "Allow users to login anonymously." Click on the edit button for this one and just toggle it on.</p><p>Then go back to the Authentication page. We'll now click on Edit for the second one which is "Email/Password."</p><p>First, enable the provider. Next, for "User Confirmation Method," choose "Automatically confirm users." MongoDB Realm provides a user confirmation workflow for your app, but in our case we don't need it.</p><p>Next comes "Password Reset Method." MongoDB Realm also provides a password reset method for your users. We won't be implementing it, but because we need to enter the configuration, just enter <code class="language-text">http://example.com/reset</code> in "Password Reset URL."</p><p>Once you're done, click Save. Our users are now able to login with an email and password.</p><p>The last step for setting up authentications is to allow users who are logged in with email and password to write their own reviews. To do that, go to rules in the sidebar, then choose the <code class="language-text">restaurants</code> collection, then click on "New Role" in the table.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Data-Sources-MongoDB-Realm2.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>A popup will open. You first need to enter the role name. We'll name it "Users"</p><p>Next, we'll need to enter "Apply When" condition, which means when should the user be considered as part of this role. We want users who are logged in with their email and password to be able to write their reviews. Enter the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"%%user.data.email"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"%exists"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>Then, for the "Document-Level Permissions" choose "Insert Documents." Once you're done, click "Done Editing."</p><p>Then, in the table click "Add Field" and type in "grades" and click the checkmark. Then check for both Read and Write for the User role. This adds the double restriction which is users are only able to write in grades, nothing else. As for Read, you can check for all fields. Then, click on the left Arrow under the "User" role name to give the User role a higher priority when matching the logged in user with the correct role. Once you're done, click on Save. The table should look like this:</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Data-Sources-MongoDB-Realm6.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>And with this done, we can now anonymous and logged in users can read all data, but only users logged in can write their own reviews.</p><p>One last thing to do is make sure to click on Review Draft & Deploy for all the changes to take effect.</p><p>Now, we have our MongoDB Realm app ready for integration with React. Next, we'll go over how to integrate it with React and use all the functionalities we've been setting up.</p><hr><h2 id="react-setup">React Setup</h2><p>In case you don't have a React project ready, run the following to create one:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-react-app restaurants-reviews <span class="token builtin class-name">cd</span> restaurants-reviews</code></pre></div><p>Next, we'll install the MongoDB Realm Web SDK:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm install --save realm-web</code></pre></div><p>That's all we need to start using Realm with React. We'll also install <a href="https://react-bootstrap.github.io/">React Bootstrap</a> to make styling easier:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm install react-bootstrap bootstrap@4.6.0</code></pre></div><p>and <a href="https://reactrouter.com/web/guides/quick-start">React Router</a> to add different pages:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm install react-router-dom</code></pre></div><p><strong>Home Page</strong></p><p>Let's first start by modifying creating the <code class="language-text">Home</code> component which will be the home page. The home page will just show a list of restaurants and their ratings.</p><p>Create the file <code class="language-text">src/pages/Home.js</code> and the following basic component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">Home</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Home</code></pre></div><p>For now, it's just a component that shows a <code class="language-text"><div></code> element. We need to make it show a list of restaurants instead. </p><p>Since we're going to fetch the restaurants from our MongoDB Realm App later on, we'll be using a state for restaurants:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">Home</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>restaurants<span class="token punctuation">,</span> setRestaurants<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">//...</span> <span class="token punctuation">}</span></code></pre></div><p>Then, we'll loop over the restaurants and display them:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"mt-3"</span><span class="token operator">></span> <span class="token punctuation">{</span>restaurants<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">restaurant</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>RestaurantCard key<span class="token operator">=</span><span class="token punctuation">{</span>restaurant<span class="token punctuation">.</span>_id<span class="token punctuation">}</span> restaurant<span class="token operator">=</span><span class="token punctuation">{</span>restaurant<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></code></pre></div><p>Let's create <code class="language-text">src/components/RestaurantCard.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> Badge <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-bootstrap'</span> <span class="token keyword">import</span> Card <span class="token keyword">from</span> <span class="token string">'react-bootstrap/Card'</span> <span class="token keyword">function</span> <span class="token function">RestaurantCard</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>restaurant<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//get average of grades</span> <span class="token keyword">let</span> sum <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> restaurant<span class="token punctuation">.</span>grades<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">element</span> <span class="token operator">=></span> <span class="token punctuation">{</span> sum <span class="token operator">+=</span> element<span class="token punctuation">.</span>score <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> avg <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">round</span><span class="token punctuation">(</span>sum <span class="token operator">/</span> <span class="token punctuation">(</span>restaurant<span class="token punctuation">.</span>grades<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Card className<span class="token operator">=</span><span class="token string">"m-3"</span><span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Body<span class="token operator">></span> <span class="token operator"><</span>Card<span class="token punctuation">.</span>Title<span class="token operator">></span><span class="token punctuation">{</span>restaurant<span class="token punctuation">.</span>name<span class="token punctuation">}</span> <span class="token operator"><</span>Badge variant<span class="token operator">=</span><span class="token string">"warning"</span><span class="token operator">></span><span class="token punctuation">{</span>avg<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>Badge<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>Card<span class="token punctuation">.</span>Title<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token punctuation">.</span>Body<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Card<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> RestaurantCard</code></pre></div><p>We're first calculating the average grade for the restaurant, then we're just displaying a card with the restaurant's name and the average grade.</p><p>So, our home page should show a list of cards with restaurant names and grades. What's left is to actually link it to the data in our Realm app.</p><p>Let's go over how to connect to Realm Apps first. You first need an App ID. You'll find the App ID on the Dashboard or you can click the copy icon in the sidebar.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Data-Sources-MongoDB-Realm5.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>Then, create a <code class="language-text">.env</code> file in the root directory with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token constant">REACT_APP_REALM_APP_ID</span><span class="token operator">=</span><span class="token operator"><</span><span class="token constant">YOUR_APP_ID</span><span class="token operator">></span></code></pre></div><p>Make sure to replace <code class="language-text"><YOUR_APP_ID></code> with the App ID you copied. This helps changing App IDs easy just by changing it in <code class="language-text">.env</code>.</p><p>Back to <code class="language-text">src/pages/Home.js</code>, we first need to import the SDK:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> Realm <span class="token keyword">from</span> <span class="token string">'realm-web'</span></code></pre></div><p>Then, initialize the Realm App:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Realm<span class="token punctuation">.</span>App</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">id</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">REACT_APP_REALM_APP_ID</span><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Notice we're using the environment variable we set earlier.</p><p>Then inside the <code class="language-text">Home</code> component, we'll use <code class="language-text">useEffect</code> to fetch the data on first render:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre></div><p>Inside, we'll log in the user anonymously and then fetch the <code class="language-text">restaurants</code> data. Since earlier we allowed all users to read all data, even users who aren't logged in can read the data.</p><p>To login a user anonymously:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token keyword">await</span> app<span class="token punctuation">.</span><span class="token function">logIn</span><span class="token punctuation">(</span>Realm<span class="token punctuation">.</span>Credentials<span class="token punctuation">.</span><span class="token function">anonymous</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre></div><p>After that, we'll get the MongoDB client for our collection using the user we just logged in:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> client <span class="token operator">=</span> app<span class="token punctuation">.</span>currentUser<span class="token punctuation">.</span><span class="token function">mongoClient</span><span class="token punctuation">(</span><span class="token string">'mongodb-atlas'</span><span class="token punctuation">)</span></code></pre></div><p>As you can tell, by using <code class="language-text">app.currentUser</code> we're referring to the currently logged-in user. Then, we get the MongoDB client for that user. This means that the access to the data is restricted based on the user that is logged in, just like we defined above.</p><p>Next step would be to get the restaurants from <code class="language-text">restaurants</code> collection and set the restaurants state:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> rests <span class="token operator">=</span> client<span class="token punctuation">.</span><span class="token function">db</span><span class="token punctuation">(</span><span class="token string">'sample_restaurants'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">collection</span><span class="token punctuation">(</span><span class="token string">'restaurants'</span><span class="token punctuation">)</span> <span class="token function">setRestaurants</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">await</span> rests<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre></div><p>And with this, our code will display the restaurants once we retrieve them from MongoDB Realm App. We'll add also some loading to make sure we can see the loading:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>restaurants<span class="token punctuation">,</span> setRestaurants<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>loading<span class="token punctuation">,</span> setLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//...</span> <span class="token keyword">const</span> rests <span class="token operator">=</span> client<span class="token punctuation">.</span><span class="token function">db</span><span class="token punctuation">(</span><span class="token string">'sample_restaurants'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">collection</span><span class="token punctuation">(</span><span class="token string">'restaurants'</span><span class="token punctuation">)</span> <span class="token function">setRestaurants</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">await</span> rests<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>loading<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>loading<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"mt-3"</span><span class="token operator">></span> <span class="token punctuation">{</span>loading <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"text-center"</span><span class="token operator">></span> <span class="token operator"><</span>Loading <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token punctuation">{</span>restaurants<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">restaurant</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>RestaurantCard key<span class="token operator">=</span><span class="token punctuation">{</span>restaurant<span class="token punctuation">.</span>_id<span class="token punctuation">}</span> restaurant<span class="token operator">=</span><span class="token punctuation">{</span>restaurant<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>We'll also create <code class="language-text">src/components/Loading.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> Spinner <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Loading</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Spinner animation<span class="token operator">=</span><span class="token string">"border"</span> variant<span class="token operator">=</span><span class="token string">"primary"</span><span class="token operator">></span> <span class="token operator"><</span>span className<span class="token operator">=</span><span class="token string">"sr-only"</span><span class="token operator">></span>Loading<span class="token operator">...</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Spinner<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Loading</code></pre></div><p>And that's it! The home page now is ready. Only thing left is to use <code class="language-text">react-router</code> in <code class="language-text">src/App.js</code> to ensure multiple pages:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> BrowserRouter <span class="token keyword">as</span> Router<span class="token punctuation">,</span> Switch<span class="token punctuation">,</span> Route<span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-router-dom"</span> <span class="token keyword">import</span> Home <span class="token keyword">from</span> <span class="token string">"./pages/Home"</span> <span class="token keyword">import</span> <span class="token string">'bootstrap/dist/css/bootstrap.min.css'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Container <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Router<span class="token operator">></span> <span class="token operator"><</span>Container<span class="token operator">></span> <span class="token operator"><</span>Switch<span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>Home<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Switch<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Router<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span> </code></pre></div><p>Let's now run the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>After some loading, you'll see the restaurants with their average grades:</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/React-App.png" class="kg-image" alt="How to Integrate MongoDB Realm with React: Part 1" loading="lazy"/></figure><p>Next, we'll create authentication forms to allow users to create accounts and login.</p><p><strong>Authentication Page</strong></p><p>Since the user just needs to enter the email and password to Sign up and Log in, we'll just create one Authentication component that changes behavior based on <code class="language-text">type</code> prop that determines whether the form is being used to create an account or login.</p><p>Before we start, let's install <a href="https://formik.org/">Formik</a> and <a href="https://github.com/jquense/yup">Yup</a> to make creating a form easier:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i formik yup</code></pre></div><p>Then, create <code class="language-text">src/pages/Authentication.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> Formik <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'formik'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Button<span class="token punctuation">,</span> Form <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-bootstrap'</span> <span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> yup <span class="token keyword">from</span> <span class="token string">'yup'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> Loading <span class="token keyword">from</span> <span class="token string">'../components/Loading'</span> <span class="token keyword">const</span> userSchema <span class="token operator">=</span> yup<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">shape</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">email</span><span class="token operator">:</span> yup<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">required</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">password</span><span class="token operator">:</span> yup<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">required</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">8</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">function</span> <span class="token function">Authentication</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>type <span class="token operator">=</span> <span class="token string">'login'</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>loading<span class="token punctuation">,</span> setLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">submitHandler</span> <span class="token punctuation">(</span><span class="token parameter">values</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token comment">//TODO handle login/create</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Formik initialValues<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">email</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token literal-property property">password</span><span class="token operator">:</span> <span class="token string">''</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> validationSchema<span class="token operator">=</span><span class="token punctuation">{</span>userSchema<span class="token punctuation">}</span> onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>submitHandler<span class="token punctuation">}</span> <span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>errors<span class="token punctuation">,</span> touched<span class="token punctuation">,</span> handleSubmit<span class="token punctuation">,</span> values<span class="token punctuation">,</span> handleChange<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>Form noValidate onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token punctuation">{</span>loading <span class="token operator">&&</span> <span class="token operator"><</span>Loading <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">}</span> <span class="token punctuation">{</span><span class="token operator">!</span>loading <span class="token operator">&&</span> <span class="token punctuation">(</span><span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span><span class="token punctuation">{</span>type <span class="token operator">===</span> <span class="token string">'login'</span> <span class="token operator">?</span> <span class="token string">'Login'</span> <span class="token operator">:</span> <span class="token string">'Sign Up'</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Row<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Email<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"email"</span> name<span class="token operator">=</span><span class="token string">"email"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>values<span class="token punctuation">.</span>email<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span>handleChange<span class="token punctuation">}</span> isValid<span class="token operator">=</span><span class="token punctuation">{</span>touched<span class="token punctuation">.</span>email <span class="token operator">&&</span> <span class="token operator">!</span>errors<span class="token punctuation">.</span>email<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control<span class="token punctuation">.</span>Feedback<span class="token operator">></span><span class="token punctuation">{</span>errors<span class="token punctuation">.</span>email<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Control<span class="token punctuation">.</span>Feedback<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Row<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Row<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span>Password<span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Label<span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control type<span class="token operator">=</span><span class="token string">"password"</span> name<span class="token operator">=</span><span class="token string">"password"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>values<span class="token punctuation">.</span>password<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span>handleChange<span class="token punctuation">}</span> isValid<span class="token operator">=</span><span class="token punctuation">{</span>touched<span class="token punctuation">.</span>password <span class="token operator">&&</span> <span class="token operator">!</span>errors<span class="token punctuation">.</span>password<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Form<span class="token punctuation">.</span>Control<span class="token punctuation">.</span>Feedback<span class="token operator">></span><span class="token punctuation">{</span>errors<span class="token punctuation">.</span>password<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Control<span class="token punctuation">.</span>Feedback<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token punctuation">.</span>Row<span class="token operator">></span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"text-center mt-2"</span><span class="token operator">></span> <span class="token operator"><</span>Button variant<span class="token operator">=</span><span class="token string">"primary"</span> type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span>Submit<span class="token operator"><</span><span class="token operator">/</span>Button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Form<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Formik<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Authentication</code></pre></div><p>We're using Formik to create a form that has two fields, email, and password. We're also using <code class="language-text">yup</code> it to create a validation schema. On form submit if everything is valid, the function <code class="language-text">submitHandler</code> will run which accepted the <code class="language-text">values</code> object.</p><p>Inside <code class="language-text">submitHandler</code>, we need to check the <code class="language-text">type</code> prop. If it equals <code class="language-text">create</code>, then we need to create a new user and login the user after that. If it's <code class="language-text">login</code> then we just need to login the user.</p><p>But before we start, as it will be a hassle to use the <code class="language-text">user</code> object, the MongoDB <code class="language-text">client</code>, and the Realm <code class="language-text">app</code>, let's create a <a href="https://reactjs.org/docs/context.html">Context</a> that allows us to use the same data throughout the components easily.</p><p>Create <code class="language-text">src/MongoContext.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">const</span> MongoContext <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">createContext</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">app</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token literal-property property">client</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token literal-property property">user</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token function-variable function">setApp</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token function-variable function">setClient</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token function-variable function">setUser</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">export</span> <span class="token keyword">default</span> MongoContext</code></pre></div><p>We're creating a Context that has the objects <code class="language-text">app</code>, <code class="language-text">client</code>, and <code class="language-text">user</code> and their setter functions <code class="language-text">setApp</code>, <code class="language-text">setClient</code> and <code class="language-text">setUser</code>.</p><p>Next, let's move declarations and intialization of <code class="language-text">user</code>, <code class="language-text">app</code> and <code class="language-text">client</code> that we did in <code class="language-text">Home</code> to <code class="language-text">App</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>client<span class="token punctuation">,</span> setClient<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>user<span class="token punctuation">,</span> setUser<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>app<span class="token punctuation">,</span> setApp<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Realm<span class="token punctuation">.</span>App</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">id</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">REACT_APP_REALM_APP_ID</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">init</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>user<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setUser</span><span class="token punctuation">(</span>app<span class="token punctuation">.</span>currentUser <span class="token operator">?</span> app<span class="token punctuation">.</span>currentUser <span class="token operator">:</span> <span class="token keyword">await</span> app<span class="token punctuation">.</span><span class="token function">logIn</span><span class="token punctuation">(</span>Realm<span class="token punctuation">.</span>Credentials<span class="token punctuation">.</span><span class="token function">anonymous</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>client<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setClient</span><span class="token punctuation">(</span>app<span class="token punctuation">.</span>currentUser<span class="token punctuation">.</span><span class="token function">mongoClient</span><span class="token punctuation">(</span><span class="token string">'mongodb-atlas'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>app<span class="token punctuation">,</span> client<span class="token punctuation">,</span> user<span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre></div><p>As you can see, we're creating states for each of them and setting them in <code class="language-text">App</code>. Then, we'll wrap our routes with <code class="language-text">MongoContext.Provider</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Router<span class="token operator">></span> <span class="token operator"><</span>MongoContext<span class="token punctuation">.</span>Provider value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span>app<span class="token punctuation">,</span> client<span class="token punctuation">,</span> user<span class="token punctuation">,</span> setClient<span class="token punctuation">,</span> setUser<span class="token punctuation">,</span> setApp<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Container<span class="token operator">></span> <span class="token operator"><</span>Switch<span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/"</span> component<span class="token operator">=</span><span class="token punctuation">{</span>Home<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Switch<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Container<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>MongoContext<span class="token punctuation">.</span>Provider<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Router<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Now, we need to pass the context to each of the components using <code class="language-text">MongoContext.Consumer</code>. To avoid repetition, let's create a function inside <code class="language-text">App</code> that does this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">renderComponent</span> <span class="token punctuation">(</span><span class="token parameter">Component<span class="token punctuation">,</span> additionalProps <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator"><</span>MongoContext<span class="token punctuation">.</span>Consumer<span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">mongoContext</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>Component mongoContext<span class="token operator">=</span><span class="token punctuation">{</span>mongoContext<span class="token punctuation">}</span> <span class="token punctuation">{</span><span class="token operator">...</span>additionalProps<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>MongoContext<span class="token punctuation">.</span>Consumer<span class="token operator">></span> <span class="token punctuation">}</span></code></pre></div><p>This will wrap a component with <code class="language-text">MongoContext.Consumer</code> then pass it the <code class="language-text">mongoContext</code> prop, which will hold all the objects we're storing in the context and their setters.</p><p>Back to the return statement in <code class="language-text">App</code>, instead of passing <code class="language-text">component={Home}</code> to the route, we'll pass a render function:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/"</span> render<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">renderComponent</span><span class="token punctuation">(</span>Home<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>Now, we have a context that holds all the objects and their setters, then we're passing it to a route's component.</p><p>Let's make changes in <code class="language-text">src/pages/Home.js</code> where instead of initialing <code class="language-text">app</code>, <code class="language-text">user</code>, and <code class="language-text">client</code>, it'll receive them as props:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useEffect<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> RestaurantCard <span class="token keyword">from</span> <span class="token string">'../components/RestaurantCard'</span> <span class="token keyword">import</span> Loading <span class="token keyword">from</span> <span class="token string">'../components/Loading'</span> <span class="token keyword">function</span> <span class="token function">Home</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span><span class="token literal-property property">mongoContext</span><span class="token operator">:</span> <span class="token punctuation">{</span>client<span class="token punctuation">,</span> user<span class="token punctuation">}</span><span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>restaurants<span class="token punctuation">,</span> setRestaurants<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>loading<span class="token punctuation">,</span> setLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> rests <span class="token operator">=</span> client<span class="token punctuation">.</span><span class="token function">db</span><span class="token punctuation">(</span><span class="token string">'sample_restaurants'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">collection</span><span class="token punctuation">(</span><span class="token string">'restaurants'</span><span class="token punctuation">)</span> <span class="token function">setRestaurants</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">await</span> rests<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>loading <span class="token operator">&&</span> user <span class="token operator">&&</span> client<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>client<span class="token punctuation">,</span> loading<span class="token punctuation">,</span> user<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"mt-3"</span><span class="token operator">></span> <span class="token punctuation">{</span>loading <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"text-center"</span><span class="token operator">></span> <span class="token operator"><</span>Loading <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token punctuation">{</span>restaurants<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">restaurant</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>RestaurantCard key<span class="token operator">=</span><span class="token punctuation">{</span>restaurant<span class="token punctuation">.</span>_id<span class="token punctuation">}</span> restaurant<span class="token operator">=</span><span class="token punctuation">{</span>restaurant<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Home</code></pre></div><p>If you try running the server and going to the website, you'll see that everything is working perfectly as before.</p><p>Back to the <code class="language-text">Authentication</code> component, we'll now pass it the <code class="language-text">mongoContext</code> prop:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">Authentication</span> <span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">mongoContext</span><span class="token operator">:</span> <span class="token punctuation">{</span>app<span class="token punctuation">,</span> user<span class="token punctuation">,</span> setUser<span class="token punctuation">}</span><span class="token punctuation">,</span> type <span class="token operator">=</span> <span class="token string">'login'</span><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Inside <code class="language-text">submitHandler</code>, if the <code class="language-text">type</code> is create we'll register a new user, then for both types we'll login the user with their credentials:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">submitHandler</span> <span class="token punctuation">(</span><span class="token parameter">values</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>type <span class="token operator">===</span> <span class="token string">'create'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//create</span> <span class="token keyword">await</span> app<span class="token punctuation">.</span>emailPasswordAuth<span class="token punctuation">.</span><span class="token function">registerUser</span><span class="token punctuation">(</span>values<span class="token punctuation">.</span>email<span class="token punctuation">,</span> values<span class="token punctuation">.</span>password<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//login user and redirect to home</span> <span class="token keyword">const</span> credentials <span class="token operator">=</span> Realm<span class="token punctuation">.</span>Credentials<span class="token punctuation">.</span><span class="token function">emailPassword</span><span class="token punctuation">(</span>values<span class="token punctuation">.</span>email<span class="token punctuation">,</span> values<span class="token punctuation">.</span>password<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setUser</span><span class="token punctuation">(</span><span class="token keyword">await</span> app<span class="token punctuation">.</span><span class="token function">logIn</span><span class="token punctuation">(</span>credentials<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>As you can see, we're using <code class="language-text">app</code> and <code class="language-text">setUser</code> from the context. When we use <code class="language-text">setUser</code>, the user will be updated for all components using the context.</p><p>Last thing we need to add is to redirect the user if they're already logged in. To do that, first create <code class="language-text">src/utils.js</code> which will hold the function <code class="language-text">isAnon</code> to determine whether the user is logged in:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token function-variable function">isAnon</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator">!</span>user <span class="token operator">||</span> user<span class="token punctuation">.</span>identities<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>providerType <span class="token operator">===</span> <span class="token string">'anon-user'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>Where <code class="language-text">providerType</code> will be <code class="language-text">anon-user</code> if the user is not logged in.</p><p>Then, inside <code class="language-text">Authentication</code>, we'll get a <code class="language-text">history</code> instance using <code class="language-text">useHistory</code> from <code class="language-text">react-router</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> history <span class="token operator">=</span> <span class="token function">useHistory</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre></div><p>Then, whenever the <code class="language-text">user</code> in the context changes, we'll check if the user is logged in and then we'll redirect to home if true.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">isAnon</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> history<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>history<span class="token punctuation">,</span> user<span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre></div><p>Our <code class="language-text">Authentication</code> component is now done! Let's add <code class="language-text">signin</code> and <code class="language-text">signup</code> routes in <code class="language-text">src/App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/signup"</span> render<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">renderComponent</span><span class="token punctuation">(</span>Authentication<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'create'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/signin"</span> render<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">renderComponent</span><span class="token punctuation">(</span>Authentication<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/"</span> render<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">renderComponent</span><span class="token punctuation">(</span>Home<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>We'll also need a <code class="language-text">LogOut</code> page so create <code class="language-text">src/pages/Logout.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useEffect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span> <span class="token keyword">import</span> Loading <span class="token keyword">from</span> <span class="token string">"../components/Loading"</span> <span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> Realm <span class="token keyword">from</span> <span class="token string">'realm-web'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useHistory <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-router"</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> isAnon <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"../utils"</span> <span class="token keyword">function</span> <span class="token function">LogOut</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span><span class="token literal-property property">mongoContext</span><span class="token operator">:</span> <span class="token punctuation">{</span>app<span class="token punctuation">,</span> setUser<span class="token punctuation">,</span> setClient<span class="token punctuation">}</span><span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> history <span class="token operator">=</span> <span class="token function">useHistory</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isAnon</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> history<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">logout</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">await</span> app<span class="token punctuation">.</span>currentUser<span class="token punctuation">.</span><span class="token function">logOut</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//login anon user</span> <span class="token function">setUser</span><span class="token punctuation">(</span><span class="token keyword">await</span> app<span class="token punctuation">.</span><span class="token function">logIn</span><span class="token punctuation">(</span>Realm<span class="token punctuation">.</span>Credentials<span class="token punctuation">.</span><span class="token function">anonymous</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">//set new client</span> <span class="token function">setClient</span><span class="token punctuation">(</span>app<span class="token punctuation">.</span>currentUser<span class="token punctuation">.</span><span class="token function">mongoClient</span><span class="token punctuation">(</span><span class="token string">'mongodb-atlas'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">logout</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>app<span class="token punctuation">,</span> setClient<span class="token punctuation">,</span> setUser<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Loading <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> LogOut</code></pre></div><p>We're first checking if the user is already not logged in and we're redirecting them to homepage if that's the case. Then, we're displaying the loading component and inside <code class="language-text">useEffect</code> we're logging the user out using:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">await</span> app<span class="token punctuation">.</span>currentUser<span class="token punctuation">.</span><span class="token function">logOut</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre></div><p>After that, we're setting the user as anonymous user again and reinitializing the MongoDB Client:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//login anon user setUser(await app.logIn(Realm.Credentials.anonymous())) //set new client setClient(app.currentUser.mongoClient('mongodb-atlas'))</code></pre></div><p>And with that, we have our log out page. We just need to add it to the routes in <code class="language-text">src/App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/signup"</span> render<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">renderComponent</span><span class="token punctuation">(</span>Authentication<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'create'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/signin"</span> render<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">renderComponent</span><span class="token punctuation">(</span>Authentication<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/logout"</span> render<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">renderComponent</span><span class="token punctuation">(</span>LogOut<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/"</span> render<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">renderComponent</span><span class="token punctuation">(</span>Home<span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span></code></pre></div><p>Lastly, we'll create a <code class="language-text">src/components/Navigation.js</code> component to show a navigation bar with our links:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> Nav<span class="token punctuation">,</span> Navbar <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-bootstrap"</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Link <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-router-dom"</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> isAnon <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"../utils"</span> <span class="token keyword">function</span> <span class="token function">Navigation</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>user<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> loggedIn <span class="token operator">=</span> <span class="token operator">!</span><span class="token function">isAnon</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Navbar bg<span class="token operator">=</span><span class="token string">"light"</span> expand<span class="token operator">=</span><span class="token string">"lg"</span><span class="token operator">></span> <span class="token operator"><</span>Navbar<span class="token punctuation">.</span>Brand href<span class="token operator">=</span><span class="token string">"#home"</span><span class="token operator">></span>Restaurant Reviews<span class="token operator"><</span><span class="token operator">/</span>Navbar<span class="token punctuation">.</span>Brand<span class="token operator">></span> <span class="token operator"><</span>Navbar<span class="token punctuation">.</span>Toggle aria<span class="token operator">-</span>controls<span class="token operator">=</span><span class="token string">"basic-navbar-nav"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Navbar<span class="token punctuation">.</span>Collapse id<span class="token operator">=</span><span class="token string">"basic-navbar-nav"</span><span class="token operator">></span> <span class="token operator"><</span>Nav className<span class="token operator">=</span><span class="token string">"mr-auto"</span><span class="token operator">></span> <span class="token operator"><</span>Link to<span class="token operator">=</span><span class="token string">"/"</span> className<span class="token operator">=</span><span class="token string">"mx-2"</span><span class="token operator">></span>Home<span class="token operator"><</span><span class="token operator">/</span>Link<span class="token operator">></span> <span class="token punctuation">{</span><span class="token operator">!</span>loggedIn <span class="token operator">&&</span> <span class="token operator"><</span>Link to<span class="token operator">=</span><span class="token string">"/signup"</span> className<span class="token operator">=</span><span class="token string">"mx-2"</span><span class="token operator">></span>Sign Up<span class="token operator"><</span><span class="token operator">/</span>Link<span class="token operator">></span><span class="token punctuation">}</span> <span class="token punctuation">{</span><span class="token operator">!</span>loggedIn <span class="token operator">&&</span> <span class="token operator"><</span>Link to<span class="token operator">=</span><span class="token string">"/signin"</span> className<span class="token operator">=</span><span class="token string">"mx-2"</span><span class="token operator">></span>Sign In<span class="token operator"><</span><span class="token operator">/</span>Link<span class="token operator">></span><span class="token punctuation">}</span> <span class="token punctuation">{</span>loggedIn <span class="token operator">&&</span> <span class="token operator"><</span>Link to<span class="token operator">=</span><span class="token string">"/logout"</span> className<span class="token operator">=</span><span class="token string">"mx-2"</span><span class="token operator">></span>Log out<span class="token operator"><</span><span class="token operator">/</span>Link<span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Nav<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Navbar<span class="token punctuation">.</span>Collapse<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Navbar<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Navigation</code></pre></div><p>We're passing it the user prop, then we're checking if the user is logged in, we'll show the log out link. If not, we'll show the sign in and sign up links.</p><p>Add the <code class="language-text">Navigation</code> component in <code class="language-text">src/App.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Router<span class="token operator">></span> <span class="token operator"><</span>Navigation user<span class="token operator">=</span><span class="token punctuation">{</span>user<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>MongoContext<span class="token punctuation">.</span>Provider value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span>app<span class="token punctuation">,</span> client<span class="token punctuation">,</span> user<span class="token punctuation">,</span> setClient<span class="token punctuation">,</span> setUser<span class="token punctuation">,</span> setApp<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token comment">//...</span> <span class="token punctuation">)</span></code></pre></div><p>We're done! Run the server if you aren't already:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm start</code></pre></div><p>You'll see we have a navigation bar that shows the sign in and sign up links when we're not logged in. Try to sign up, log out, sign it, do different things. To check if the users are actually being created, on the Realm platform, click on "App Users" in the sidebar. You'll see a list of users with the type of user either Anonymous or Email/Password.</p><hr><h2 id="conclusion">Conclusion</h2><p>In the next part, we'll add a form for users to create their own reviews. We'll be able to test the permissions we added earlier and see how the users are restricted based on the roles we create.</p><p>You can read part 2 <a href="https://blog.shahednasser.com/how-to-integrate-mongodb-realm-with-react-part-2/">here</a>.</p></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[How to Search Through Different Social Media Platforms with Node.js]]></title><description><![CDATA[In this tutorial, we'll go over how to search through each of Twitter, Instagram, Tumblr, and Pinterest.]]></description><link>https://blog.shahednasser.com/how-to-search-through-different-social-media-platforms-with-node-js/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ea4</guid><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sun, 09 May 2021 16:06:30 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/d2c465ef3cda7fa061a1d8f9542195a9/photo-1504270997636-07ddfbd48945.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/d2c465ef3cda7fa061a1d8f9542195a9/photo-1504270997636-07ddfbd48945.jpg" alt="How to Search Through Different Social Media Platforms with Node.js"/><p>In this tutorial, we'll go over how to search through each of Twitter, Instagram, Tumblr, and Pinterest. We'll be setting up a server with <code class="language-text">express</code> with a simple setup just to demonstrate the functionalities.</p><p>You can find the code for this tutorial in <a href="https://github.com/shahednasser/social-search">this GitHub repository</a>.</p><hr><h2 id="project-setup">Project Setup</h2><p>Create a directory for the project then switch to it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> social-search <span class="token builtin class-name">cd</span> social-search</code></pre></div><p>Next, let's initialize it with NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> init</code></pre></div><p>You can enter any information that's relevant for you, or just leave the default values.</p><p>Once done, we'll install some initial packages we'll need:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i express axios dotenv</code></pre></div><p>Where <code class="language-text">express</code> is for our server, <code class="language-text">axios</code> is to send requests which we'll use with some of the social media platforms, and <code class="language-text">dotenv</code> which we'll use to store necessary tokens in <code class="language-text">.env</code>.</p><p>Then, create a file called <code class="language-text">index.js</code> in the root with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'dotenv'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'express'</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> axios <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'axios'</span><span class="token punctuation">)</span> app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token number">3000</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"started server for social search!"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>This will create a simple server that listens on port 3000. Last thing we'll need to do to start our server is add a <code class="language-text">start</code> script in <code class="language-text">package.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"start"</span><span class="token operator">:</span> <span class="token string">"node index.js"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>That's it! To test our server, let's run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>If everything worked correctly, you'll see a message saying "started server for social search!"</p><p>Now, we're ready to start searching through social media.</p><hr><h2 id="searching-twitter">Searching Twitter</h2><p>To search Twitter, you first need to <a href="https://developer.twitter.com/en/portal/apps/new">create a new app</a> on twitter's developer portal. Depending on whether this is your first app or not, you might need to enter some extra information, but generally you just need to enter the name of the app.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-05-09-at-4.03.53-PM.png" class="kg-image" alt="How to Search Through Different Social Media Platforms with Node.js" loading="lazy"/></figure><p>Then, you will be given the API key and the API secret. Make sure to copy them and save them somewhere.</p><p>Once the app is created, go to "Keys and Tokens" tab on the app's page. Under "Authentication Tokens", click on "Generate" for Access Token and Secret. You will be given two extra keys that you need to copy and save somewhere.</p><p>Back to our project, create <code class="language-text">.env</code> file which will hold the keys:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">TWITTER_API_KEY= TWITTER_API_SECRET= TWITTER_ACCESS_TOKEN= TWITTER_ACCESS_TOKEN_SECRET=</code></pre></div><p>where the first 2 keys are the first 2 you received, and the second 2 are the ones you generated.</p><p>To access Twitter's API easily, we'll use the library <a href="https://github.com/FeedHive/twitter-api-client">twitter-api-client</a>. It provides an easy to use interface to access Twitter's APIs. We need to install it first with NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i twitter-api-client</code></pre></div><p>Now, go to <code class="language-text">index.js</code>, require the library and initialize the Twitter client:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> TwitterClient <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'twitter-api-client'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>TwitterClient <span class="token keyword">const</span> twitterClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TwitterClient</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">apiKey</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_API_KEY</span><span class="token punctuation">,</span> <span class="token literal-property property">apiSecret</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_API_SECRET</span><span class="token punctuation">,</span> <span class="token literal-property property">accessToken</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_ACCESS_TOKEN</span><span class="token punctuation">,</span> <span class="token literal-property property">accessTokenSecret</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_ACCESS_TOKEN_SECRET</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Since we've added at the beginning of the file <code class="language-text">require('dotenv').config()</code>, we can now use the keys we added in <code class="language-text">.env</code> through <code class="language-text">process.env</code>.</p><p>Next, we'll add a new GET route that takes <code class="language-text">query</code> parameter, which we'll use to search through Twitter:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/twitter/:query'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Inside the callback function for this route, we need to search through twitter for tweets including this given query. To search tweets, we'll use the <code class="language-text">twitterClient.tweets.search</code> which takes as a parameter an object that includes various properties. The one we'll use is <code class="language-text">q</code> which we'll pass the query:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> query <span class="token operator">=</span> req<span class="token punctuation">.</span>params<span class="token punctuation">.</span>query twitterClient<span class="token punctuation">.</span>tweets<span class="token punctuation">.</span><span class="token function">search</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">q</span><span class="token operator">:</span> query <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">'An error occurred, please try again later.'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>When we get a response, we're just sending it back. If an error occurs, we're printing it to the console and sending a status 500 response.</p><p>That's it! To test it out, start the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>Then go to the route we specified, passing it any query you want. For example, localhost:3000/twitter/cats. If everything is done correctly, you should see a JSON object that holds an array of tweets.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screen-Shot-2021-05-09-at-6.02.50-PM.png" class="kg-image" alt="How to Search Through Different Social Media Platforms with Node.js" loading="lazy"/></figure><p>You can look at the <a href="https://github.com/FeedHive/twitter-api-client/blob/main/REFERENCES.md#twitterclienttweetssearchparameters">documentation for twitter-api-client</a> to understand more the options you can pass, the response, etc...</p><hr><h2 id="searching-instagram">Searching Instagram</h2><p>Instagram APIs are a mess. Long story short, now there's <a href="https://developers.facebook.com/docs/instagram-api/guides/hashtag-search/">Hashtag Search</a> that can be accessed through <a href="https://developers.facebook.com/docs/instagram-api">Instagram Graph API</a>. However, this only allows you to search through posts of a certain user, not search in general. Not to mention that this API needs you to access a bunch of endpoints in order to finally get the posts with the hashtag you're querying.</p><p>There's another <strong>unofficial</strong> way to search through Instagram. There's an endpoint you can find at <a href="https://www.instagram.com/explore/tags/test/?__a=1">https://www.instagram.com/explore/tags/KEYWORD/?__a=1</a>, where when you replace KEYWORD with the query, you'll get a JSON response with all the posts using the hashtag.</p><p>We'll create a new endpoint that allows us to search through Instagram:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/instagram/:query'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Inside the callback, we'll use <code class="language-text">axios</code> to send a GET request to the endpoint we mentioned above, then send back the response once received:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> query <span class="token operator">=</span> req<span class="token punctuation">.</span>params<span class="token punctuation">.</span>query axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'https://www.instagram.com/explore/tags/'</span> <span class="token operator">+</span> query <span class="token operator">+</span> <span class="token string">'/?__a=1'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>response<span class="token punctuation">.</span>data<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">'An error occurred, please try again later.'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>That's it. To test it out, start the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>Then, go to the route we just created, passing it the query you want. For example, localhost:3000/instagram/cats. If everything was done correctly, the response will be a JSON object with the posts using the hashtag cats.</p><hr><h2 id="searching-tumblr">Searching Tumblr</h2><p>To search through Tumblr, first <a href="https://www.tumblr.com/oauth/apps">register a new application</a>. You'll need a tumblr account to do that. You'll have to enter information like Application name, Application URL (you can just enter http://example.com), etc...</p><p>Once done, you'll be redirected to the Applications page and it will show you the newly created app. You can see the OAuth Consumer Key. Copy it and add it to <code class="language-text">.env</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">TUMBLR_CONSUMER_KEY=</code></pre></div><p>To search posts by tags, we can use the <a href="https://www.tumblr.com/docs/en/api/v2#tagged--get-posts-with-tag"><code class="language-text">/tagged</code> endpoint</a>. We'll pass it the API key, which is the Consumer key we just added to <code class="language-text">.env</code>, and the tag which is the query we're searching.</p><p>First, we'll create the new GET route:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/tumblr/:query'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> query <span class="token operator">=</span> req<span class="token punctuation">.</span>params<span class="token punctuation">.</span>query <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>As usual, we're creating a route that takes a query as a parameter.</p><p>Then, we'll send a GET request to Tumblr's <code class="language-text">/tagged</code> endpoint using <code class="language-text">axios</code> passing it the parameter as explained above:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'https://api.tumblr.com/v2/tagged?tag='</span> <span class="token operator">+</span> query <span class="token operator">+</span> <span class="token string">'&api_key='</span> <span class="token operator">+</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TUMBLR_CONSUMER_KEY</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>response<span class="token punctuation">.</span>data<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">'An error occurred, please try again later.'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>As before, we're just sending back the response once received.</p><p>To test it out, start the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>Then, go to the route we created passing it the query you want. For example, localhost:3000/tumblr/cats. If everything is working correctly, the response will be a JSON response with an array of posts using the tag cats.</p><hr><h2 id="searching-pinterest">Searching Pinterest</h2><p>Pinterest doesn't have an API that allows you to search through their pins. To search through Pinterest, we'll have to use <a href="https://developers.google.com/custom-search/v1/overview">Google's Custom Search JSON API</a>. This API allows you to retreive search results in JSON format. We'll use it to search through Pinterest. It's not optimal, but at the moment of writing this, it's the easiest way. You should note that this API provides 100 queries per day for free, then you'll be billed 5$ for every additional 1000 query.</p><p>First, you'll need to get an <a href="https://developers.google.com/custom-search/v1/overview#api_key">API key</a> to use. Just click the "Get a Key" button. It will ask you to create a project or use an existing one, then you'll be provided with an API key. Copy the key and add it to <code class="language-text">.env</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">CUSTOM_SEARCH_API_KEY=</code></pre></div><p>Next, you'll need to create a "Programmable Search". You can do that <a href="https://cse.google.com/cse/create/new">here</a>. You'll need to enter the URL of the site you'll be searching. In our case it will be pinterest.com. You can also change the language and Name of the Programmable Search. Once done, click Create. It will take you to a page that will show you a bunch of options. Choose "Control Panel" button.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Programmable-Search-Congratulations-.png" class="kg-image" alt="How to Search Through Different Social Media Platforms with Node.js" loading="lazy"/></figure><p>Once you're on the Control Panel, copy the "Search Engine ID" and add it to <code class="language-text">.env</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">CUSTOM_SEARCH_CX=</code></pre></div><p>We'll need to pass this as a parameter when we send our requests to the API.</p><p>Let's start by creating the GET route to query Pinterest:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/pinterest/:query'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> query <span class="token operator">=</span> req<span class="token punctuation">.</span>params<span class="token punctuation">.</span>query <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Next, we'll send a request to the Custom Search API endpoint passing it the API key, CX which is the Search Engine ID, and the query we're searching:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'https://www.googleapis.com/customsearch/v1?key='</span> <span class="token operator">+</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">CUSTOM_SEARCH_API_KEY</span> <span class="token operator">+</span> <span class="token string">'&cx='</span> <span class="token operator">+</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">CUSTOM_SEARCH_CX</span> <span class="token operator">+</span> <span class="token string">'&q='</span> <span class="token operator">+</span> query<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>items<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">'An error occurred, please try again later.'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>As usual, we're just sending back the response received.</p><p>To test it out, start the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre></div><p>Then, go to the route we just created, passing it a query. For example, localhost:3000/pinterest/cats. You'll see a JSON array, each object having the title of the pin, the link to it, and other information.</p><hr><h2 id="conclusion">Conclusion</h2><p>In this tutorial, we went over searching Twitter, Instagram, Tumblr, and Pinterest. In the next one, we'll go through searching more social media platforms!</p></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[How to Make Your Front-End Development Faster in Magento 2 Using Grunt]]></title><description><![CDATA[We'll go over how to use Magento's out-of-the-box commands in Grunt, and how to add our own to make our development faster.]]></description><link>https://blog.shahednasser.com/how-to-make-your-front-end-development-faster-in-magento-2-using-grunt/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ea3</guid><category><![CDATA[Magento]]></category><category><![CDATA[PHP]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 08 May 2021 21:25:17 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/e647eb234b69ccebdfa01cd65cfe0f68/magento-grunt-banner--1-.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/e647eb234b69ccebdfa01cd65cfe0f68/magento-grunt-banner--1-.png" alt="How to Make Your Front-End Development Faster in Magento 2 Using Grunt"/><p>Magento 2 is a great e-commerce platform, as it comes with many features built-in. It makes it easier for store owners to create a store that exactly fits their needs.</p><p>However, developing with Magento can be a pain, as it is not easy to learn, and even when you do, there is a lot of build or compilation required for a lot of minor changes, especially for front-end development.</p><p>Here's where Grunt comes in. Grunt is a Javascript task runner that helps in automating repeated tasks like compilation, minification, etc... </p><p>We'll go over how to use Magento's out-of-the-box commands in Grunt, and how to add our own to make our development faster.</p><hr><h3 id="install-grunt-cli">Install Grunt-CLI</h3><p>If you don't have <code class="language-text">grunt-cli</code> installed globally, you need to install it with the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> -g grunt-cli</code></pre></div><p>If you get an error that permission is denied, you'll need to run the command as <code class="language-text">sudo</code> or on Windows, you'll need to run PowerShell or Command Prompt as an administrator.</p><hr><h3 id="setting-up-magento-with-grunt">Setting up Magento with Grunt</h3><p>If you look at your Magento project directory, you'll see that in the root there are two files: <code class="language-text">package.json</code> and <code class="language-text">package.json.sample</code>. If you open <code class="language-text">package.json</code>, it will be just an empty JSON object like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><span class="token punctuation">}</span></code></pre></div><p>But if you open <code class="language-text">package.json.sample</code>, you'll find a proper <code class="language-text">package.json</code> that will look something like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">{ "name": "magento2", "author": "Magento Commerce Inc.", "description": "Magento2 node modules dependencies for local development", "license": "(OSL-3.0 OR AFL-3.0)", "repository": { "type": "git", "url": "https://github.com/magento/magento2.git" }, "homepage": "http://magento.com/", "devDependencies": { "glob": "~7.1.1", "grunt": "~1.0.1", "grunt-autoprefixer": "~3.0.4", "grunt-banner": "~0.6.0", "grunt-continue": "~0.1.0", "grunt-contrib-clean": "~1.1.0", "grunt-contrib-connect": "~1.0.2", "grunt-contrib-cssmin": "~2.2.1", "grunt-contrib-imagemin": "~2.0.1", "grunt-contrib-jasmine": "~1.1.0", "grunt-contrib-less": "~1.4.1", "grunt-contrib-watch": "~1.0.0", "grunt-eslint": "~20.1.0", "grunt-exec": "~3.0.0", "grunt-jscs": "~3.0.1", "grunt-replace": "~1.0.1", "grunt-styledocco": "~0.3.0", "grunt-template-jasmine-requirejs": "~0.2.3", "grunt-text-replace": "~0.4.0", "imagemin-svgo": "~5.2.1", "load-grunt-config": "~0.19.2", "morgan": "~1.9.0", "node-minify": "~2.3.1", "path": "~0.12.7", "serve-static": "~1.13.1", "squirejs": "~0.2.1", "strip-json-comments": "~2.0.1", "time-grunt": "~1.4.0", "underscore": "~1.8.0" } }</code></pre></div><p>So, we'll remove the current <code class="language-text">package.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">rm</span> package.json</code></pre></div><p>then rename the <code class="language-text">package.json.sample</code> to <code class="language-text">package.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">mv</span> package.json.sample package.json</code></pre></div><p>After that, we'll install the dependencies using NPM:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span></code></pre></div><p>Once the installation is done, you'll have a new <code class="language-text">node_modules</code> directory with all the dependencies we'll need to run grunt.</p><p>The next step would be to set up <code class="language-text">Gruntfile.js</code> which holds the tasks to be run by Grunt. You'll find a <code class="language-text">Gruntfile.js.sample</code> in the root directory, so we'll just have to rename it to <code class="language-text">Gruntfile.js</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">mv</span> Gruntfile.js.sample Gruntfile.js</code></pre></div><p>By default in Magento, the following tasks are one of those defined in Grunt:</p><ol><li><strong>default</strong>: Just shows a default message in the terminal.</li><li><strong>clean</strong>: cleans the directories that hold the cached or generated files. </li><li><strong>deploy</strong>: generates static files.</li><li><strong>refresh</strong>: cleans cache and refreshes the generated static files.</li></ol><p>Usually, in Magento, when making changes in modules or themes to assets like Javascript, LESS, or CSS files, you'll need to run the following command to see the file changes in action:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php bin/magento setup:static-content:deploy -f</code></pre></div><p>Magento claims that this is unnecessary in development, which is why we use <code class="language-text">-f</code>, however, if you've used Magento you'll know that this is actually not true and you need to run this command whenever you need to see the changes you made.</p><p>Actually, prior to running that command, you'll probably also need to remove directories like <code class="language-text">var/cache</code> or <code class="language-text">var/page_cache</code>, or you'll need to run commands that clears and flushes the cache.</p><p>Running all these different commands can be such a hassle, and this is where Grunt comes in. You can do all that just with a simple command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">grunt refresh</code></pre></div><p>This command first runs the <code class="language-text">clean</code> command, which will clear up all the directories holding the cache, then will compile all themes and their assets.</p><p><strong>Compiling Your Custom Theme</strong></p><p>Grunt compiles the themes that are declared in <code class="language-text">dev/tools/grunt/configs/themes.js</code>. The declaration for a theme looks something like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token literal-property property">blank</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">area</span><span class="token operator">:</span> <span class="token string">'frontend'</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Magento/blank'</span><span class="token punctuation">,</span> <span class="token literal-property property">locale</span><span class="token operator">:</span> <span class="token string">'en_US'</span><span class="token punctuation">,</span> <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'css/styles-m'</span><span class="token punctuation">,</span> <span class="token string">'css/styles-l'</span><span class="token punctuation">,</span> <span class="token string">'css/email'</span><span class="token punctuation">,</span> <span class="token string">'css/email-inline'</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">dsl</span><span class="token operator">:</span> <span class="token string">'less'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>As you can see, the key of the object is the name of the theme. It has the following properties:</p><ol><li><strong>area</strong>: Where the theme applies. Can be <code class="language-text">frontend</code>, <code class="language-text">adminhtml</code>, or <code class="language-text">doc</code>.</li><li><strong>name</strong>: The name of the theme, which is in the format <code class="language-text">VENDOR_THEME</code>.</li><li><strong>locale</strong>: The locale of the theme.</li><li><strong>files</strong>: These are the files in the theme that should be compiled.</li><li><strong>dsl</strong>: stands for <code class="language-text">dynamic stylesheet language</code> and can be either <code class="language-text">less</code> or <code class="language-text">sass</code></li></ol><p>So, to make sure your theme is compiled when running <code class="language-text">grunt refresh</code>, you'll need to add your theme to this object, with the values for the properties based on your theme.</p><hr><h2 id="adding-custom-tasks">Adding Custom Tasks</h2><p>The next part we'll go over is how to create custom tasks in Grunt that will help make our development faster.</p><p>One use case we can automate is when we update a module's version. Usually, you have to run 3 different tasks:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php bin/magento setup:upgrade</code></pre></div><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php bin/magento setup:di:compile</code></pre></div><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">php bin/magento setup:static-content:deploy -f</code></pre></div><p>We'll create a new task called <code class="language-text">upgrade</code> that will run all these tasks for us.</p><p>To create a new task, you need to create a new file in <code class="language-text">dev/tools/grunt/tasks</code>. We'll create a new file there called <code class="language-text">upgrade.js</code>.</p><p>The file should export a function that takes <code class="language-text">grunt</code> as a parameter:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">grunt</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//TODO code for the task</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div><p>the reason behind this is that <code class="language-text">Gruntfile.js</code> fetches all files in the <code class="language-text">tasks</code> directory, and passes them the instance of <code class="language-text">grunt</code>.</p><p>Next, we'll declare some functions that will be helpful for us:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> exec <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'child_process'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>execSync<span class="token punctuation">,</span> log <span class="token operator">=</span> grunt<span class="token punctuation">.</span>log<span class="token punctuation">.</span>write<span class="token punctuation">,</span> ok <span class="token operator">=</span> grunt<span class="token punctuation">.</span>log<span class="token punctuation">.</span>ok</code></pre></div><ol><li><code class="language-text">exec</code>: it's actually the function <code><a href="https://nodejs.org/api/child_process.html#child_process_child_process_execsync_command_options">execSync</a></code> which allows us to run commands we would run in shell. We'll use it to run the commands mentioned above.</li><li><code class="language-text">log</code>: A function that allows us to output information messages.</li><li><code class="language-text">ok</code>: A function that allows us to output successful messages.</li></ol><p>Next, to register our task, we'll use <code class="language-text">grunt.registerTask</code> which takes two parameters: the name of the task and the function that the task will execute once called.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">grunt<span class="token punctuation">.</span><span class="token function">registerTask</span><span class="token punctuation">(</span><span class="token string">'upgrade'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>The first thing the task should do is run the command <code class="language-text">php bin/magento setup:upgrade</code>. We'll use <code class="language-text">exec</code> to run it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">log('Running setup:upgrade...') exec('php bin/magento setup:upgrade', {stdio: 'inherit'})</code></pre></div><p>The first parameter is the command to run, and the second parameter is an options object. The option we're passing is <code class="language-text">stdio</code> with the value <code class="language-text">inherit</code>, which means that the output should be printed to the terminal we're calling the task from.</p><p>Next, we need to run the command <code class="language-text">php bin/magento setup:di:compile</code>. We'll also use <code class="language-text">exec</code> to do that:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Running setup:di:compile'</span><span class="token punctuation">)</span> <span class="token function">exec</span><span class="token punctuation">(</span><span class="token string">'php bin/magento setup:di:compile'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">stdio</span><span class="token operator">:</span> <span class="token string">'inherit'</span><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Lastly, we need to run the command <code class="language-text">php bin/magento setup:static-content:deploy -f</code>. Instead of running it through exec, we'll run another grunt task which is the <code class="language-text">deploy</code> task since it's already declared and does all the work for us:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Running deploy...'</span><span class="token punctuation">)</span> grunt<span class="token punctuation">.</span>task<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token string">'deploy'</span><span class="token punctuation">)</span> <span class="token function">ok</span><span class="token punctuation">(</span><span class="token string">'Upgrade finished!'</span><span class="token punctuation">)</span></code></pre></div><p>We run a grunt task with <code class="language-text">grunt.task.run</code> passing it the name of the task. In the end, we're just outputting a successful message to show that our task is done.</p><p>That's it! <code class="language-text">upgrade.js</code> should look like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">grunt</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> exec <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'child_process'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>execSync<span class="token punctuation">,</span> log <span class="token operator">=</span> grunt<span class="token punctuation">.</span>log<span class="token punctuation">.</span>write<span class="token punctuation">,</span> ok <span class="token operator">=</span> grunt<span class="token punctuation">.</span>log<span class="token punctuation">.</span>ok grunt<span class="token punctuation">.</span><span class="token function">registerTask</span><span class="token punctuation">(</span><span class="token string">'upgrade'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Running setup:upgrade...'</span><span class="token punctuation">)</span> <span class="token function">exec</span><span class="token punctuation">(</span><span class="token string">'php bin/magento setup:upgrade'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">stdio</span><span class="token operator">:</span> <span class="token string">'inherit'</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Running setup:di:compile'</span><span class="token punctuation">)</span> <span class="token function">exec</span><span class="token punctuation">(</span><span class="token string">'php bin/magento setup:di:compile'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">stdio</span><span class="token operator">:</span> <span class="token string">'inherit'</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Running deploy...'</span><span class="token punctuation">)</span> grunt<span class="token punctuation">.</span>task<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token string">'deploy'</span><span class="token punctuation">)</span> <span class="token function">ok</span><span class="token punctuation">(</span><span class="token string">'Upgrade finished!'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Let's test it out. In the terminal run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">grunt upgrade</code></pre></div><p>If everything is done correctly, the task will run all 3 commands. This task will make it easier next time you need to upgrade because of a new or updated module!</p><p>Now, you can automate any task with the same process. Create a file in <code class="language-text">dev/tools/grunt/tasks</code> that exports a function that takes <code class="language-text">grunt</code> as a parameter. Inside the function, register the task using <code class="language-text">grunt.registerTask</code> and you can add whatever functionality you need inside.</p><hr><h2 id="conclusion">Conclusion</h2><p>Using Grunt with Magento, you can automate so many tasks that will make your development faster and easier! I suggest that once you start using Grunt with Magento, you keep all the tasks you create for all your projects, as it will be very beneficial.</p></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[List of Resources for Demo Data and Images]]></title><description><![CDATA[When working on any project, you'll need to use demo data to showcase the functionalities you've implemented.]]></description><link>https://blog.shahednasser.com/list-of-resources-for-demo-data-and-images/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ea2</guid><category><![CDATA[Tips]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 29 Apr 2021 08:21:11 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/624a01bfef4652252a6447f7e57a7441/photo-1483736762161-1d107f3c78e1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/624a01bfef4652252a6447f7e57a7441/photo-1483736762161-1d107f3c78e1.jpg" alt="List of Resources for Demo Data and Images"/><p>When working on any project, you'll need to use demo data to showcase the functionalities you've implemented. </p><p>So, I've compiled a list of websites, APIs, or resources, in general, you can use to get demo images and data easily.</p><hr><h2 id="images">Images</h2><h3 id="lorem-picsum"><a href="https://picsum.photos/">Lorem Picsum</a></h3><p>Lorem Picsum allows you to easily get random images. You can specify the size, make them grayscale, make them blurred, and much more.</p><p>Here's an example of using it:</p><!--kg-card-begin: html--><img src="https://picsum.photos/600/400" class="kg-image" alt="List of Resources for Demo Data and Images"><!--kg-card-end: html--><p>Every time you refresh the page, the image will change! </p><h3 id="unsplash-source"><a href="https://source.unsplash.com/">Unsplash Source</a></h3><p>Unsplash provides this simple API that allows you to get random images as well. You can specify a query (for example, "human" to get images with humans), the size of the image, and much more.</p><p>Here's an example of specifying the image and adding the query "programming":</p><!--kg-card-begin: html--><img src="https://source.unsplash.com/600x400/?programming" class="kg-image" alt="List of Resources for Demo Data and Images"><!--kg-card-end: html--><p>This image will also change everytime you refresh the page.</p><h3 id="placekitten"><a href="https://placekitten.com/">placekitten</a></h3><p>placekitten allows you to easily get placeholder random cat images, because who wouldn't love making their demo a little cuter.</p><p>An example of using it:</p><!--kg-card-begin: html--><img src="https://placekitten.com/600/400" class="kg-image" alt="List of Resources for Demo Data and Images"><!--kg-card-end: html--><h3 id="pikachu-images"><a href="https://some-random-api.ml/img/pikachu">Pikachu Images</a> </h3><p>This one allows you to get random Pikachu images. (I've actually used it in my tutorial: <a href="https://blog.shahednasser.com/chrome-extension-tutorial-replace-images-in-any-website-with-pikachu/">Chrome Extension Tutorial — Replace Images in Any Website with Pikachu</a>)</p><p>This one returns a JSON object with the link to the image, so it's different than the other services.</p><h3 id="loremflickr"><a href="https://loremflickr.com/">LoremFlickr</a></h3><p>Another source for random images that allows you to specify the size, query, or color of the image, among other options.</p><p>Here's an example of using it:</p><!--kg-card-begin: html--><img src="https://loremflickr.com/600/400" class="kg-image" alt="List of Resources for Demo Data and Images"><!--kg-card-end: html--><hr><h2 id="data">Data</h2><h3 id="faker-js"><a href="https://github.com/marak/Faker.js/">Faker.js</a> </h3><p>a Javascript library that allows you to generate fake data easily, with so many types of data. Data types include fake credit card numbers, addresses, IPs, e-commerce data, and more!</p><p>You can also find it for <a href="https://github.com/fzaninotto/Faker">PHP</a>, <a href="https://github.com/faker-ruby/faker">Ruby</a>, and <a href="https://github.com/joke2k/faker">Python</a> among others.</p><h3 id="jsonplaceholder"><a href="https://jsonplaceholder.typicode.com/">JSONPlaceholder</a></h3><p>JSONPlaceholder provides a fake REST API for free. You can get data like posts, comments, todos, users, and more.</p><p>For example, if you send a request to <a href="https://jsonplaceholder.typicode.com/posts/1">https://jsonplaceholder.typicode.com/posts/1</a>, you can get the following response:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"userId"</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">"id"</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"sunt aut facere repellat provident occaecati excepturi optio reprehenderit"</span><span class="token punctuation">,</span> <span class="token property">"body"</span><span class="token operator">:</span> <span class="token string">"quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"</span> <span class="token punctuation">}</span></code></pre></div><h3 id="mockend"><a href="https://mockend.com/">Mockend</a></h3><p>Mockend allows you to do the same as JSONPlaceholder, but with data structure more relevant to your project.</p><h3 id="req-res"><a href="https://reqres.in/">REQ|RES</a></h3><p>It provides an easy REST API with fake data that you can use. It only provides fake user data. It even provides POST, PATCH, PUT, and DELETE requests.</p><p>You can also use this to simulate different response codes, like their "User not found" endpoint returns a status code of 404.</p><h3 id="fake-store-api"><a href="https://fakestoreapi.com/">Fake Store API</a></h3><p>It provides fake e-commerce demo data to make your online store project's demo data more realistic.</p><p>Here's an example response of using their endpoint <a href="https://fakestoreapi.com/products/1">https://fakestoreapi.com/products/1</a> to get one product:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"id"</span><span class="token operator">:</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">"title"</span><span class="token operator">:</span><span class="token string">"Fjallraven - Foldsack No. 1 Backpack, Fits 15 Laptops"</span><span class="token punctuation">,</span> <span class="token property">"price"</span><span class="token operator">:</span><span class="token number">109.95</span><span class="token punctuation">,</span> <span class="token property">"description"</span><span class="token operator">:</span><span class="token string">"Your perfect pack for everyday use and walks in the forest. Stash your laptop (up to 15 inches) in the padded sleeve, your everyday"</span><span class="token punctuation">,</span> <span class="token property">"category"</span><span class="token operator">:</span><span class="token string">"men's clothing"</span><span class="token punctuation">,</span> <span class="token property">"image"</span><span class="token operator">:</span><span class="token string">"https://fakestoreapi.com/img/81fPKd-2AYL._AC_SL1500_.jpg"</span> <span class="token punctuation">}</span></code></pre></div><h3 id="my-fake-api"><a href="https://myfakeapi.com/">My Fake API</a></h3><p>It provides fake endpoints to manage users like sign up or log in, retrieve cars list, and more.</p><p>An example response of calling their endpoint <a href="https://myfakeapi.com/api/cars/1">https://myfakeapi.com/api/cars/1</a> which retrieves car of id 1:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><span class="token property">"Car"</span><span class="token operator">:</span><span class="token punctuation">{</span><span class="token property">"id"</span><span class="token operator">:</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token property">"car"</span><span class="token operator">:</span><span class="token string">"Mitsubishi"</span><span class="token punctuation">,</span><span class="token property">"car_model"</span><span class="token operator">:</span><span class="token string">"Montero"</span><span class="token punctuation">,</span><span class="token property">"car_color"</span><span class="token operator">:</span><span class="token string">"Yellow"</span><span class="token punctuation">,</span><span class="token property">"car_model_year"</span><span class="token operator">:</span><span class="token number">2002</span><span class="token punctuation">,</span><span class="token property">"car_vin"</span><span class="token operator">:</span><span class="token string">"SAJWJ0FF3F8321657"</span><span class="token punctuation">,</span><span class="token property">"price"</span><span class="token operator">:</span><span class="token string">"$2814.46"</span><span class="token punctuation">,</span><span class="token property">"availability"</span><span class="token operator">:</span><span class="token boolean">false</span><span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre></div><h3 id="fake-filler"><a href="https://chrome.google.com/webstore/detail/fake-filler/bnjjngeaknajbdcgpfkgnonkmififhfo/related">Fake Filler</a></h3><p>Fake Filler is a browser extension that easily allows you to generate fake data for your forms on the go. All you have to do after installing it is click on the icon of the extension when you're on any page that has a form, and it will do all the tedious work for you!</p><p> You can also find it for <a href="https://microsoftedge.microsoft.com/addons/detail/fake-filler/bdcjobafgkjgckiikonbfcdocnhnaaii">Edge</a> and <a href="https://addons.mozilla.org/en-US/firefox/addon/fake-filler/">Firefox</a>.</p></hr></img></img></img></img></hr>]]></content:encoded></item><item><title><![CDATA[How to Override Classes in PHP and Composer]]></title><description><![CDATA[In this tutorial, we'll cover how to override classes using Composer.]]></description><link>https://blog.shahednasser.com/how-to-override-classes-in-php-and-composer/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ea1</guid><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sun, 25 Apr 2021 10:51:40 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/a285d0358b0d1a2814e39c151f066738/photo-1488590528505-98d2b5aba04b.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/a285d0358b0d1a2814e39c151f066738/photo-1488590528505-98d2b5aba04b.jpg" alt="How to Override Classes in PHP and Composer"/><p>If you're working with PHP, maybe using Laravel or some other framework, in this tutorial, we'll cover how to override classes using Composer.</p><p>This is helpful when you are using a library or package and want to override a certain functionality, but you can't really edit the code directly.</p><hr><h3 id="prerequisites">Prerequisites</h3><p>This tutorial assumes you already have a project that uses Composer, thus having a <code class="language-text">composer.json</code> file. </p><hr><h3 id="but-first-what-s-psr-4">But First, What's PSR-4</h3><p>PSR stands for PHP Standard Recommendation. PSR-4 specifies standards for namespaces, class names, etc...</p><p>For example, let's say you have the following file structure in your project:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">- app | |_ _ _ Model | |_ _ User.php</code></pre></div><p>This is similar to the structure you'd have when using Laravel. PSR-4's standards say that the namespace should be exactly similar to the file structure. So, inside <code class="language-text">User.php</code> the namespace should be <code class="language-text">app/Model</code>.</p><p>However, when we're using Laravel we always capitalize <code class="language-text">app</code>, so the namespace would be <code class="language-text">App\Model</code>. How is that not breaking the standard?</p><p>Well, that's because of the following lines in <code class="language-text">composer.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"autoload"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"psr-4"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"App\\"</span><span class="token operator">:</span> <span class="token string">"app/"</span><span class="token punctuation">,</span> <span class="token comment">//....</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>So, how does this work?</p><hr><h3 id="autoloading-with-composer">Autoloading with Composer</h3><p>Using the <code class="language-text">autoload</code> key, we can specify how to autoload certain files based on the specification, which in this case is <code class="language-text">psr-4</code>.</p><p>So, first, we add the <code class="language-text">autoload</code> key, which is an object that has the key <code class="language-text">psr-4</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"autoload"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"psr-4"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>Inside the <code class="language-text">psr-4</code> object, we'll have key-value pairs that specify how the files should be autoloaded. The key will be the namespace to be loaded, and the value is where it should be loaded from. So, in the example of Laravel, the <code class="language-text">App\</code> namespace is the key and <code class="language-text">app/</code> is the value. That means that all <code class="language-text">App\</code> namespaces should be loaded from the <code class="language-text">app</code> directory.</p><hr><h3 id="how-to-use-this-for-overriding-classes">How to Use This for Overriding Classes</h3><p>Let's say we have a class <code class="language-text">Vendor\Model\User</code> and we want to override that class. First, the class that overrides it should be in a specific directory. So, maybe you can create the path <code class="language-text">app/overrides</code> to place your overriding classes inside. It can be any path you want it doesn't matter. </p><p>Let's say we created <code class="language-text">app/overrides/User.php</code>. We want this class to override <code class="language-text">Vendor/Model/User</code>. The first step is we need to make sure that <code class="language-text">app/overrides/User.php</code> has the same namespace:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token keyword">namespace</span> <span class="token package">Vendor</span><span class="token operator">/</span>Model<span class="token punctuation">;</span></code></pre></div><p>You can then place whatever code you want inside the class. </p><p>Next, we need to let Composer know where to autoload the namespace <code class="language-text">Vendor/Model</code> from. So, the key here should be <code class="language-text">Vendor/Model</code>, and the value should be the path to the directory that has the overriding class, which in our case is <code class="language-text">app/overrides</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"autoload"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"psr-4"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"Vendor\\Model\\"</span><span class="token operator">:</span> <span class="token string">"app/overrides"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>That's it. Now, the autoloading for <code class="language-text">Vendor/Model</code> will be from <code class="language-text">app/overrides</code> instead of the original place, and this way you can override any class you want.</p><hr><h3 id="extra-options">Extra Options</h3><p>Instead of the value being a string of the path the namespace should be loaded from, you can provide an array. This tells Composer that it should look for the classes in multiple places:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"Vendor\\Model\\"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"app/overrides"</span><span class="token punctuation">,</span> <span class="token string">"src"</span><span class="token punctuation">]</span></code></pre></div><p>You can also provide a fallback directory for any namespace:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">"autoload": { "psr-4": { "": "app/overides/" } }</code></pre></div></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[How to Send Notifications in Chrome Extensions]]></title><description><![CDATA[In this tutorial, we'll go over how to send notifications in Chrome and how to schedule notifications to be sent at a later time.]]></description><link>https://blog.shahednasser.com/how-to-send-notifications-in-chrome-extensions/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382ea0</guid><category><![CDATA[Browser Extensions]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 24 Apr 2021 12:42:13 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/7edbba770fd95ec4f780bf135c21b595/photo-1602080858428-57174f9431cf.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/7edbba770fd95ec4f780bf135c21b595/photo-1602080858428-57174f9431cf.jpg" alt="How to Send Notifications in Chrome Extensions"/><p>In this tutorial, we'll go over how to send notifications in Chrome Extensions. We'll go over how to send one notification, and how to schedule notifications to be sent at a later time.</p><hr><h3 id="prerequisites">Prerequisites</h3><p>This tutorial assumes you already know how to create a Chrome extension. If you don't, then <a href="https://blog.shahednasser.com/chrome-extension-tutorial-replace-images-in-any-website-with-pikachu/">here</a> is one you can start with first.</p><hr><h3 id="setting-permissions">Setting Permissions</h3><p>Before you can send any type of notification, you need to first add in your <code class="language-text">manifest.json</code> in <code class="language-text">permissions</code> key the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"permissions"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"notifications"</span> <span class="token comment">//other permissions in your extension</span> <span class="token punctuation">]</span></code></pre></div><p>This means that the user when installing or updating your extension has to accept that they will receive notifications in order to use the extension.</p><hr><h3 id="send-a-notification">Send a Notification</h3><p>To send a notification, you need to use the <a href="https://developer.chrome.com/docs/extensions/reference/notifications">Notifications API</a>. In particular, the <code class="language-text">chrome.notifications.create</code> method which takes the following required options:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>notifications<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">'NOTFICATION_ID'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'basic'</span><span class="token punctuation">,</span> <span class="token literal-property property">iconUrl</span><span class="token operator">:</span> <span class="token string">'path'</span><span class="token punctuation">,</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'notification title'</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'notification message'</span><span class="token punctuation">,</span> <span class="token literal-property property">priority</span><span class="token operator">:</span> <span class="token number">2</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Here's what each of these options means:</p><ol><li><strong>NOTIFICATION_ID: </strong>The id of the notification. This can be necessary for updating the notification or clearing it.</li><li><strong>type: </strong>The type of notification. Its values can be "basic", "image", "list", "progress"</li><li><strong>iconUrl: </strong>The path to the icon that should be shown in the notification. This should be relative to the root of your extension.</li><li><strong>title: </strong>the title of the notification.</li><li><strong>message: </strong>the message to be shown in the notification.</li><li><strong>priority: </strong>this one is not required, but I recommend including it. The value for it can range from -2 to 2, where -2 is the lowest priority and 2 is the highest. The default for this option is 0, so your notifications can go by unseen if you don't include this option. It should also be noted that a value less than 0 will produce an error on devices that don't have a notification center.</li></ol><p>There are some other options that are optional:</p><ul><li><strong>buttons: </strong>buttons that you want to be shown in the notification. This takes an array of buttons with at most 2 buttons. The array should be an object with the property <code class="language-text">title</code> which will be the title of the button. For example:</li></ul><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token literal-property property">buttons</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Yes'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'No'</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span></code></pre></div><ul><li><strong>contextMessage: </strong>This message will be shown in a lower font weight.</li><li><strong>eventTime: </strong>Timestamp associated with the notification. For example:</li></ul><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token literal-property property">eventTime</span><span class="token operator">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre></div><ul><li><strong>items: </strong>This will only be shown for Mac OS X. This could be useful for notifications of type <code class="language-text">list</code>. For example:</li></ul><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token literal-property property">items</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Item 1'</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'This is first item'</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span></code></pre></div><ul><li><strong>progress: </strong>This can be useful for notifications of type <code class="language-text">progress</code>. It takes a value between 0 and 100</li><li><strong>requiresInteraction: </strong>This one will only work for Chrome versions since 50. The value for this is boolean. If set to true, it means that the notification will not disappear from the screen until the user interacts with the message by either clicking on it or dismissing it. The default value for this is false.</li><li><strong>silent: </strong>This one will only work for Chrome versions since 70. The value of this is boolean. If set to true, then the notification will not make sound or vibration. The default is false.</li></ul><p>To send a basic notification that just shows a message to the user:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>notifications<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">'test'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'basic'</span><span class="token punctuation">,</span> <span class="token literal-property property">iconUrl</span><span class="token operator">:</span> <span class="token string">'images/1.png'</span><span class="token punctuation">,</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Test Message'</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'You are awesome!'</span><span class="token punctuation">,</span> <span class="token literal-property property">priority</span><span class="token operator">:</span> <span class="token number">2</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This will send one notification at the moment it's executed.</p><hr><h3 id="scheduling-notifications">Scheduling Notifications</h3><p>In a lot of cases, you don't actually want to send the notification now or you want to send notification at some interval like once a day. For this, we will use the <a href="https://developer.chrome.com/docs/extensions/reference/alarms/">Alarms API</a>.</p><p>Alarms allow us to schedule something to be run at a later time. When you create an alarm, you can specify the time interval it will run at. Then, you can listen to the alarm and when it runs executes whatever code you want.</p><p> To be able to use Alarms, we need to also include it in our permissions in <code class="language-text">manifest.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"permissions"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"alarms"</span><span class="token punctuation">,</span> <span class="token string">"notifications"</span> <span class="token comment">//other permissions your extension require</span> <span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div><p>To send notifications at a certain schedule, here's how the workflow goes:</p><ol><li>Create an alarm that runs at certain intervals</li><li>Listen for when the alarm runs</li><li>When the alarm runs, execute some logic and create a notification</li></ol><p><strong>Create an alarm that runs at certain intervals</strong></p><p>To create an alarm, we will use the method <code class="language-text">chrome.alarms.create</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>alarms<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">'ALARM_NAME'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token comment">//options</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>You only need to specify the name of the alarm <code class="language-text">ALARM_NAME</code>, which will be used later when listening to the alarm. No other options are required. However, if you use it without options, the alarm will run only once at the time it was created.</p><p>The options you can pass are:</p><ul><li><strong>when: </strong>When should the alarm start working. If you want it to start right away:</li></ul><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token literal-property property">when</span><span class="token operator">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre></div><ul><li><strong>periodInMinutes: </strong>This is where we specify when the alarm will run. It takes a number, which is the number of minutes between each time the alarm fires. So, if I want the alarm to be fired every five minutes:</li></ul><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token literal-property property">periodInMinutes</span><span class="token operator">:</span> <span class="token number">5</span></code></pre></div><ul><li><strong>delayInMinutes: </strong>This specifies if the <code class="language-text">onAlarm</code> event should delay a little before firing.</li></ul><p>The most important option here is <code class="language-text">periodInMinutes</code>. It specifies when do we want to create our notification. </p><p>So, if we want to create an alarm that will let us create a notification that runs everyday:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>alarm<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">'testAlarm'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">periodInMinutes</span><span class="token operator">:</span> <span class="token number">1440</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p><strong>Listen for when the alarm runs</strong></p><p>The next step would be to listen when the alarm runs. This should be usually done in background scripts for Manifest V2, or service workers for Manifest V3.</p><p><em>You can read more about the differences between Manifest V2 and V3 <a href="https://blog.shahednasser.com/chrome-extension-tutorial-migrating-to-manifest-v3-from-v2">here</a>.</em></p><p>If you don't know what a background script is, it's, as its name says, a script that's always running in the background, even if your extension's page or pop up or whatever your extension uses is not open or running. This helps us listen to events, alarms, messages, etc... at all times.</p><p>Service workers were introduced in Manifest V3 as a replacement for background scripts. The main difference is service workers are not always running. Service workers register event listeners to alarms, messages, etc... same as background scripts, so only the listeners run when necessary like when an event occurs.</p><p>If you don't already have a background script in your chrome extension, you need to first include it in <code class="language-text">manifest.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"js/background.js"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"persistent"</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>Or if you're using Manifest V3 you need to register a service worker: </p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"service_worker"</span><span class="token operator">:</span> <span class="token string">"js/background.js"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>Then, in the script, we will listen to the alarm using <code class="language-text">chrome.alarms.onAlarm.addListener</code> which takes a callback function, which will be our listener. This callback function will be executed every time an alarm in our extension is run, so we need to make sure we only listen to the alarm we need which we named <code class="language-text">testAlarm</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>alarms<span class="token punctuation">.</span>onAlarm<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">alarm</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>alarm<span class="token punctuation">.</span>name <span class="token operator">===</span> <span class="token string">"testAlarm"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//our alarm is running, send notification</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>We need to check that <code class="language-text">alarm.name === "testAlarm"</code> to make sure that our notifications alarm is running. This is important if you have multiple alarms in your extension as well to make sure you're executing the desired logic for the correct alarm.</p><p>So, if the condition is true, we can create the notification.</p><h3 id="when-the-alarm-runs-execute-some-logic-and-create-a-notification">When the alarm runs, execute some logic and create a notification</h3><p>Depending on your use case, you might execute some logic, maybe send a request to a server or any other logic, then run the notification. </p><p>What we will do is that we'll just create the message when the alarm runs. This is how it can be done:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>alarms<span class="token punctuation">.</span>onAlarm<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">alarm</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>alarm<span class="token punctuation">.</span>name <span class="token operator">===</span> <span class="token string">"testAlarm"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> chrome<span class="token punctuation">.</span>notifications<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">'test'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'basic'</span><span class="token punctuation">,</span> <span class="token literal-property property">iconUrl</span><span class="token operator">:</span> <span class="token string">'images/1.png'</span><span class="token punctuation">,</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Test Message'</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'You are awesome!'</span><span class="token punctuation">,</span> <span class="token literal-property property">priority</span><span class="token operator">:</span> <span class="token number">2</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>After these 3 steps, our extension will create an alarm that will run once a day and executes the code in the listener we added to the <code class="language-text">onAlarm</code> event. This listener will create a notification. Thus, a notification will be sent to the user every day.</p><hr><h3 id="sending-a-notification-on-firefox">Sending a Notification on Firefox</h3><p>Sending a notification on Firefox is exactly the same, except you just need to replace <code class="language-text">chrome.*</code> in all of the methods used with <code class="language-text">browser.*</code>. You can read more about the difference between Firefox and Chrome <a href="https://blog.shahednasser.com/making-your-extension-compatible-with-both-chrome-and-firefox/">here</a>.</p><hr><h3 id="summary">Summary</h3><p>To create a notification you need to:</p><ol><li>Add <code class="language-text">notifications</code> to the <code class="language-text">permissions</code> array in <code class="language-text">manifest.json</code></li><li>Use <code class="language-text">chrome.notifications.create</code> to create a notification and send it.</li></ol><p>To schedule a notification to run at an interval of time, you need to:</p><ol><li>Add <code class="language-text">alarms</code> to the <code class="language-text">permissions</code> array in <code class="language-text">manifest.json</code></li><li>Use <code class="language-text">chrome.alarms.create</code> to create an alarm.</li><li>Listen to the alarm with <code class="language-text">chrome.alarms.onAlarm.addListener</code> and create a notification inside the listener.</li></ol></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Answering All The "What Motivates You" Questions]]></title><description><![CDATA[I decided to write an article answering all the "what motivates you" questions I get in the hopes that it helps someone out there.]]></description><link>https://blog.shahednasser.com/answering-all-the-what-motivates-you-questions/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e9f</guid><category><![CDATA[My Experience]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 17 Apr 2021 13:21:32 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/28e71d2d1d6d70d4529d65f1ba72da7d/photo-1564410267841-915d8e4d71ea.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/28e71d2d1d6d70d4529d65f1ba72da7d/photo-1564410267841-915d8e4d71ea.jpg" alt="Answering All The "What Motivates You" Questions"/><p>Ever since I started my blog, I keep getting questions from different people about how I stay motivated. The question can be related to work, programming, writing, or other topics.</p><p>It's not an easy question, to be honest. Staying motivated can be related to different aspects of your life that can affect how you end up getting things done. With time, it can even end up being a skill you need to develop.</p><p> That's why I decided to write an article answering the different questions regarding what motivates me in the hopes that it can help someone out there.</p><hr><h3 id="what-motivates-you-to-work">What Motivates You to Work</h3><p>This one you hear a lot of people ask, regardless of who you are or what your profession is. The answer to this can be different for every person. Some people might think about the money they're making or the financial security the job provides. Others might think about the responsibilities they have in a job and how it's important for them to stay on top of everything.</p><p>For me, what I learned through looking at different people's lives, applying to different jobs, and my experience at my job, what keeps me motivated is the work environment. It's easy to fall for job titles or salaries when choosing a job, but, in my personal opinion, what actually keeps you going is a healthy work environment.</p><p>A healthy work environment is where you can make mistakes and get help to fix them without having to worry or feel scared about making them. It's a place where you can discuss your work with your colleagues in a professional manner regardless of your age, gender, level of knowledge, or anything similar. It's a place where you can feel like you're a part of a team, where you either rise up together or fall together. It's where you feel safe to make mistakes, learn, and grow.</p><p>Having a good work environment keeps me going even when I'm feeling very demotivated or tired. Seeing everyone else work hard and wanting the best for the entire team makes me want to work just as hard. The end result we achieve together makes everything worth it. That's what keeps me motivated to go to work every day and keep trying.</p><hr><h3 id="what-motivates-you-to-write">What Motivates You to Write</h3><p>I've always loved writing, even before becoming a programmer and starting with technical writings and articles. Starting a blog was something I've always wanted to do. However, I still go through times where I just don't want to do it anymore. When I'm too busy with other responsibilities, It doesn't feel as important and I end up dropping it for a while. </p><p>The reason I still get back to it is that for me writing in my own blog is a learning journey. It's not just putting together a bunch of words or who's gonna read it. It's about learning something new and then sharing it with others in case they're looking for the same information or are interested to learn about the same things as well.</p><hr><h3 id="what-motivates-you-to-do-programming-of-any-kind-outside-of-work">What Motivates You to Do Programming of Any Kind Outside of Work</h3><p>If you've read any of my previous articles or if you follow me on GitHub or Twitter, you'll know that I manage a couple of open source projects and I also have some free browser extensions I develop and maintain. Working on projects that are not classified as "work" can be hard sometimes, especially when you have a lot of actual work and responsibilities taking a lot of your time. You end up not having the time to spend it on programming outside of the work scope. </p><p>In my own opinion, contributing to open source projects or working on personal projects that do not necessarily generate profit for you is a good way to improve your programming skills, engage with the community, and keep your love for programming going. A lot of time in work scenarios you might not be in control of the tasks, the programming language, or other aspects due to the type of work. Once you confine programming to just your job, it will stop being something you love and it will become something you tolerate or have to do to earn a living. Although that's not bad, I'd like to work in what I like. </p><p>So, I try to keep working on projects outside of the work spectrum to keep myself in shape. To make sure I'm still learning something new, to stay in the know, and to have something that I'm fully in control of. To build something of my own. Even if no one else uses it, I will still benefit from it in all the ways I mentioned above. Once I remind myself of that, I always find my way back to it even if I lose motivation. </p><hr><h3 id="what-motivates-you-to-keep-learning">What Motivates You to Keep Learning</h3><p>Regardless of the field you are working in, the longer you work in it or as you get older, you might get to a point where you are used to what you know and use and you don't seek new information and knowledge regarding what's changing in the world. Specifically, in our field, you have to constantly keep up with the new technologies, skills, and methods that are coming out every now and then. Using the same old technologies can sometimes result in outdated products. We have to keep learning and keep growing with the growth of technology.</p><p>I think this one sums up everything else I mentioned before. I keep myself motivated to learn by keeping myself motivated to work, as I learn from real-life situations and problems, learn from my colleague's expertise, or learn new technologies based on new projects or requirements. I keep myself motivated to learn by keeping myself motivated to write, as I sometimes learn something to write about it or as I research things more thoroughly. I keep myself motivated to learn by doing personal projects or contributing to open source projects.</p><p>As long as you're staying active in different fields, or even one field that you are 100% focused on that you're giving it all your motivation, skills, effort, and energy, you'll want to flourish in it and will end up learning on the go.</p><hr><h3 id="conclusion">Conclusion</h3><p>It's not always easy to stay motivated, but if you keep trying and keep reminding yourself of why you are doing what you are doing, you'll learn how to self-motivate yourself.</p><p>Do you have other ways or reasons to stay motivated? Please share them with me on my twitter <a href="https://twitter.com/shahednasserr">@shahednasserr </a></p></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[React Custom Hooks Tutorial - Creating useOnline, Testing and Publishing It]]></title><description><![CDATA[In this tutorial, we'll go over how to create a simple custom React hook, testing it locally, and then publishing it on NPM.]]></description><link>https://blog.shahednasser.com/react-custom-hooks-tutorial-creating-useonline/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e9e</guid><category><![CDATA[React]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 08 Apr 2021 09:32:22 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/be8d82122ad723252c06e1df3beb3094/photo-1536859355448-76f92ebdc33d.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/be8d82122ad723252c06e1df3beb3094/photo-1536859355448-76f92ebdc33d.jpg" alt="React Custom Hooks Tutorial - Creating useOnline, Testing and Publishing It"/><p>In this tutorial, we'll go over how to create a simple custom React hook, testing it locally, and then publishing it on NPM. The React hook we'll create is <code class="language-text">useOnline</code> which detects if the user goes offline and shows them a message that they're offline.</p><p>After implementing it, we'll check how we can test it locally, then publishing it on NPM.</p><p>If you're checking out this tutorial to learn only how to create a custom hook to use it in an existing project without intending on publishing it as a package on NPM, then you can stop before the testing and publishing part of this tutorial. You probably also won't need to go through the Setup part as well.</p><p> The code for this tutorial is available on <a href="https://github.com/shahednasser/use-online">this GitHub Repository</a>.</p><hr><h3 id="what-are-custom-hooks">What are Custom Hooks?</h3><p>Custom hooks hold a certain logic that make use of React's hooks like useState, useEffect, etc... You usually create custom hooks when a certain part in your project is reusable and makes use of React's hooks. So, you create a custom hook that you can use throughout your project just like you would use React's hooks. It should also start with <code class="language-text">use</code>.</p><hr><h3 id="setup">Setup</h3><p>Let's start by creating a new directory and changing to it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> use-online <span class="token builtin class-name">cd</span> use-online</code></pre></div><p>Then, we'll initialize our NPM project:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> init</code></pre></div><p>You'll have to enter some information that will go into <code class="language-text">package.json</code> like package name, description, author, main entry, etc... You can use the default settings for now.</p><p>Once you're done, you'll have an empty NPM package at your hand. Let's now install the dependencies we'll be using to develop our custom React hook:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i --save-dev react @babel/cli copyfiles</code></pre></div><p>We're installing React since we are developing a custom hook. We're also installing babel's CLI to build our code later on, and we're installing copyfiles which we will use later as well when we are getting our package ready for publishing.</p><p>Once we're done with that, we're ready to implement our custom hook.</p><hr><h3 id="implementing-useonline">Implementing useOnline</h3><p>As I mentioned in the beginning, <code class="language-text">useOnline</code> will detect whenever the user is online or offline. This means that it will manage a state for the user's connectivity status, and listen to any changes in the user's connectivity and update it accordingly.</p><p>So, <code class="language-text">useOnline</code> will make use of <code class="language-text">useStatus</code> to keep track of the user's connectivity, and will use <code class="language-text">useEffect</code> to register event listeners for the events <code class="language-text">online</code> and <code class="language-text">offline</code> to set the state accordingly. In the end, <code class="language-text">useOnline</code> will just return the state which we can use in other components to track the user's connectivity without repeating the logic behind it.</p><p>Let's start by creating the file that will hold our custom hook. Create <code class="language-text">src/useOnline.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useEffect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">function</span> <span class="token function">useOnline</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> useOnline</code></pre></div><p>We're just importing <code class="language-text">useState</code> and <code class="language-text">useEffect</code> to use them in a bit, declaring the custom hook <code class="language-text">useOnline</code> and exporting it.</p><p>Now, let's get to the code of the hook. First, let's create the state that will hold the user's connectivity:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">useOnline</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>online<span class="token punctuation">,</span> setOnline<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span>navigator<span class="token punctuation">.</span>onLine<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p><code class="language-text">online</code> will hold the state of the user's connectivity and it will be a boolean. If the user is online it will be true, if not it will be false. For its initial value, we are using the value of <code class="language-text">navigator.onLine</code> which returns the online status of the browser.</p><p>Next, we need to listen to the <code class="language-text">online</code> and <code class="language-text">offline</code> events. The <code class="language-text">online</code> event occurs when the user goes online, and the <code class="language-text">offline</code> event occurs when the user goes offline. To add the listeners, we will use <code class="language-text">useEffect</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">useOnline</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>online<span class="token punctuation">,</span> setOnline<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span>navigator<span class="token punctuation">.</span>onLine<span class="token punctuation">)</span> <span class="token function">useEffect</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'online'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//TODO change state to online</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'offline'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//TODO change state to offline</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>So, we are adding event listeners to the <code class="language-text">online</code> and <code class="language-text">offline</code> events inside <code class="language-text">useEffect</code> callback. We are also passing an empty array as a second parameter for <code class="language-text">useEffect</code>. This ensures that the callback is only called on mounting the component.</p><p>Now, let's add the logic inside each of the listeners. We just need to change the value of <code class="language-text">online</code> based on the event. To do this, we will use <code class="language-text">setOnline</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">useEffect</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'online'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setOnline</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'offline'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setOnline</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre></div><p>Pretty easy. Our code now adds an event listener to both <code class="language-text">online</code> and <code class="language-text">offline</code> events, which change the value of our state <code class="language-text">online</code> based on the user's connectivity.</p><p>When adding event listeners or adding any kind of subscriptions, we need to make sure that we are cleaning up after the component unmounts. To do that, we return a function in <code class="language-text">useEffect</code> that removes the event listeners on unmount.</p><p>Since we will be using <code class="language-text">removeEventListener</code> to remove the event listeners, which takes the event listener we are moving as a second parameter, let's remove our event listeners to functions that we can reference:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">offlineHandler</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setOnline</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">onlineHandler</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setOnline</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">useEffect</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'online'</span><span class="token punctuation">,</span> onlineHandler<span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'offline'</span><span class="token punctuation">,</span> offlineHandler<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> window<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span><span class="token string">'online'</span><span class="token punctuation">,</span> onlineHandler<span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span><span class="token string">'offline'</span><span class="token punctuation">,</span> offlineHandler<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre></div><p>We moved our event listeners to functions outside <code class="language-text">useEffect</code> (you can also add them inside instead) and we are passing them as the event listeners in <code class="language-text">addEventListener</code> and <code class="language-text">removeEventListener</code> inside <code class="language-text">useEffect</code> for both the <code class="language-text">online</code> and <code class="language-text">offline</code> events.</p><p>The last thing we need to do in our custom hook is return the state we are changing. This way we can use this state in other components with all the logic behind it in one place.</p><p>So, the full code for <code class="language-text">useOnline</code> will be:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useEffect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">function</span> <span class="token function">useOnline</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>online<span class="token punctuation">,</span> setOnline<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span>navigator<span class="token punctuation">.</span>onLine<span class="token punctuation">)</span> <span class="token keyword">function</span> <span class="token function">offlineHandler</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setOnline</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">onlineHandler</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setOnline</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">useEffect</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setOnline</span><span class="token punctuation">(</span>navigator<span class="token punctuation">.</span>onLine<span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'online'</span><span class="token punctuation">,</span> onlineHandler<span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'offline'</span><span class="token punctuation">,</span> offlineHandler<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> window<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span><span class="token string">'online'</span><span class="token punctuation">,</span> onlineHandler<span class="token punctuation">)</span> window<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span><span class="token string">'offline'</span><span class="token punctuation">,</span> offlineHandler<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">return</span> online <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> useOnline<span class="token punctuation">;</span></code></pre></div><p>That's it! We created a custom hook that makes use of React hooks like <code class="language-text">useState</code> and <code class="language-text">useEffect</code> to determine the user's connectivity.</p><hr><h3 id="preparing-the-npm-package">Preparing the NPM Package</h3><p>If you want to publish your custom hook on NPM, you need to prepare the package to be published and used. There are certain things that need to be done, especially in <code class="language-text">package.json</code>.</p><p>In the beginning, we installed <code class="language-text">@babel/cli</code> and <code class="language-text">copyfiles</code>. This is where we'll put them into use.</p><p><strong>Package Information</strong></p><p>When you first run <code class="language-text">npm init</code> you are asked to enter a few information like package name, description, author, version, license, etc... If you've used the default information, or you want to change this information, make sure you change them prior to publishing. You can do that in the <code class="language-text">package.json</code> file. </p><p>Note that the <code class="language-text">name</code> in <code class="language-text">package.json</code> is the package name that people will use to install it. So, make sure it's exactly what you want to call it. </p><p><strong>Dependencies</strong></p><p>When publishing a package, make sure you are listing the dependencies required correctly. If some dependencies are only required during development and are not necessary to install when they are being used, then include them under <code class="language-text">devDependencies</code>.</p><p>In our example, we should have:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"devDependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"react"</span><span class="token operator">:</span> <span class="token string">"^17.0.1"</span><span class="token punctuation">,</span> <span class="token property">"@babel/cli"</span><span class="token operator">:</span> <span class="token string">"^7.13.14"</span><span class="token punctuation">,</span> <span class="token property">"copyfiles"</span><span class="token operator">:</span> <span class="token string">"^2.4.1"</span> <span class="token punctuation">}</span></code></pre></div><p>Note that the versions might be different in your project but that's fine. </p><p>There's one more thing to note: In a React project, only one installation or instance of <code class="language-text">react</code> is allowed. Meaning that your package shouldn't install React as well when installing it in a project.</p><p>So, let's change <code class="language-text">react</code> to be a peer dependency like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"peerDependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"react"</span><span class="token operator">:</span> <span class="token string">"^16.8.0 || ^17.0.1"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"devDependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"@babel/cli"</span><span class="token operator">:</span> <span class="token string">"^7.13.14"</span><span class="token punctuation">,</span> <span class="token property">"copyfiles"</span><span class="token operator">:</span> <span class="token string">"^2.4.1"</span> <span class="token punctuation">}</span></code></pre></div><p>When adding a dependency in <code class="language-text">peerDependencies</code>, the <code class="language-text">react</code> package you are using in your project that will include this package will be used instead of installing a new one. We are also allowing the version to be at least <code class="language-text">16.8.0</code> since that's when React Hooks were introduced.</p><p><strong>Scripts</strong></p><p>To make sure our package is ready for use, we will add scripts that will build our React custom hook using <code class="language-text">babel</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"prebuild"</span><span class="token operator">:</span> <span class="token string">"npm i"</span><span class="token punctuation">,</span> <span class="token property">"build"</span><span class="token operator">:</span> <span class="token string">"babel src --out-dir dist"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>Now, whenever we run <code class="language-text">build</code>, <code class="language-text">prebuild</code> will run first to ensure that the dependencies required are installed, then the build script will compile the Javascript files in our <code class="language-text">src</code> directory (which is <code class="language-text">useOnline.js</code>) and outputs the result in <code class="language-text">dist</code>.</p><p><strong>main</strong></p><p>If we want our package to be used like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> useOnline <span class="token keyword">from</span> <span class="token string">'use-online'</span></code></pre></div><p>Then we need to specify what we are exporting and which file will be used for the import. It's the <code class="language-text">main</code> file in our package.</p><p>In our case, it will be the output of the <code class="language-text">build</code> script:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"main"</span><span class="token operator">:</span> <span class="token string">"dist/useOnline.js"</span></code></pre></div><p><strong>files</strong></p><p>When publishing a package, by default, it will publish all the files and directories starting from the root directory. This can increase the package's size significantly, especially if there are a lot of redundant files or files that are not necessary for the package to be used.</p><p>In our example, if you look at the <a href="https://github.com/shahednasser/use-online">GitHub Repository</a>, you can see that there's an <code class="language-text">example</code> directory. We will get to what that holds later, but a lot of times you might have examples, images, or other files that might be necessary for the package development-wise, but not when it's published.</p><p>To decrease the package size and make sure only relevant files are included, we use the <code class="language-text">files</code> key:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"files"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"dist"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div><p><code class="language-text">files</code> takes an array that holds all the files or directories that should be included in the package once published. In our case, it will just be the <code class="language-text">dist</code> directory that will hold our built code.</p><p><strong>types</strong></p><p>This one is purely optional and I'm using it in its simplest form. You can add a Typescript declaration for your package. To do so, we'll create <code class="language-text">src/useOnline.d.ts</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="ts"><pre class="language-ts"><code class="language-ts"><span class="token keyword">declare</span> <span class="token keyword">module</span> <span class="token string">'use-online'</span> <span class="token punctuation">{</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">useOnline</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">boolean</span> <span class="token punctuation">}</span></code></pre></div><p>This will declare the module <code class="language-text">use-online</code> which exports the function <code class="language-text">useOnline</code> that returns boolean which is the online status.</p><p>Next, we will add a new script in <code class="language-text">package.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"prebuild"</span><span class="token operator">:</span> <span class="token string">"npm i"</span><span class="token punctuation">,</span> <span class="token property">"build"</span><span class="token operator">:</span> <span class="token string">"babel src --out-dir dist"</span><span class="token punctuation">,</span> <span class="token property">"postbuild"</span><span class="token operator">:</span> <span class="token string">"copyfiles -u 1 ./src/useOnline.d.ts ./dist"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>The <code class="language-text">postbuild</code> script will run after the <code class="language-text">build</code> script is finished. It will copy <code class="language-text">src/useOnline.d.ts</code> to the <code class="language-text">dist</code> directory.</p><p>Last, we will add the <code class="language-text">types</code> key in <code class="language-text">package.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"types"</span><span class="token operator">:</span> <span class="token string">"dist/useOnline.d.ts"</span><span class="token punctuation">,</span></code></pre></div><p>This will make your package a Typescript package, although in Typescript packages you wouldn't really be doing it this way. This is just a simple form of how to do it. </p><hr><h3 id="testing-our-custom-hook-locally">Testing Our Custom Hook Locally</h3><p>If you are adding your custom hook to your existing project, then you can probably just test it there. However, if you are creating a custom hook to publish online, and you want to test it as a separate package, this section is for you.</p><p>In the <a href="https://github.com/shahednasser/use-online">GitHub Repository</a> I created for this tutorial, you can see an <code class="language-text">example</code> folder. This folder holds a website built using <code class="language-text">create-react-app</code> that is just used to test our <code class="language-text">use-online</code> package that holds the <code class="language-text">useOnline</code> hook.</p><p>If you don't have a project to test <code class="language-text">use-online</code>, let's create one just for the purpose by running the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx create-react-app example</code></pre></div><p>This will create a new directory <code class="language-text">example</code> that will hold a Single Page Application (SPA) built with React. </p><p>Before changing into that directory. Let's look into how we'd use <code class="language-text">use-online</code> if it's not actually a package on NPM. As you probably already know, you can install any package on NPM using the <code class="language-text">install</code> or <code class="language-text">i</code> command like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token operator"><</span>PACKAGE_NAME<span class="token operator">></span></code></pre></div><p>However, how do we install a package that is only available locally? We will you <a href="https://docs.npmjs.com/cli/v7/commands/npm-link">linking</a>.</p><p><code class="language-text">npm-link</code> allows us to create a symlink of our package in the global folder on our machine. This way, we can "install" local packages in other projects on our machine for purposes like testing.</p><p>What we will do is we will create a link of <code class="language-text">use-online</code>, then use it in the <code class="language-text">example</code> project we just created.</p><p>Inside the root directory of <code class="language-text">use-online</code> run the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">link</span></code></pre></div><p>Once this is done, a symbolic link will be created to this package. We can now change to the example directory and "install" the <code class="language-text">use-online</code> package by linking to it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> example <span class="token function">npm</span> <span class="token function">link</span> use-online</code></pre></div><p>Once linked, you can now use <code class="language-text">use-online</code> in this project as if it was installed like any other NPM package. Any changes you make in <code class="language-text">use-online</code> will automatically be portrayed in the package.</p><p>Before we can use <code class="language-text">use-online</code>, let's go its root directory and run the build command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm run build</code></pre></div><p>This will run NPM install, compiles the code with <code class="language-text">babel</code>, then (if you followed along with the typescript part) copies the typescript declaration file to <code class="language-text">dist</code></p><p>I recommend before testing it you remove the <code class="language-text">node_modules</code> directory. As we mentioned before, when using <code class="language-text">peerDependencies</code> React will not be installed if the project you are installing <code class="language-text">use-online</code> into already has it installed. However, when we ran the build command, the package was on its own and there was no <code class="language-text">react</code> dependencies installed so it installed <code class="language-text">react</code>. Since we are linking to it and not actually installing it in <code class="language-text">example</code>, the <code class="language-text">node_modules</code> directory of <code class="language-text">use-online</code> will be inside the <code class="language-text">node_modules</code> directory of <code class="language-text">example</code>, which will lead to two <code class="language-text">react</code> instances inside <code class="language-text">example</code>. So, make sure to delete <code class="language-text">node_modules</code> in <code class="language-text">use-online</code> before testing it.</p><p>We will just be adding three 3 lines in <code class="language-text">example/src/App.js</code>. First, we will import our custom hook:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> useOnline <span class="token keyword">from</span> <span class="token string">'use-online'</span></code></pre></div><p>Second, inside the <code class="language-text">App</code> component, we will use the <code class="language-text">useOnline</code> hook to get the <code class="language-text">online</code> state:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> online <span class="token operator">=</span> <span class="token function">useOnline</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//... rest of the code</span> <span class="token punctuation">}</span></code></pre></div><p>Third and last, we will add in the rendered part a condition to display to the user that they're offline:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"App"</span><span class="token operator">></span> <span class="token operator"><</span>header className<span class="token operator">=</span><span class="token string">"App-header"</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token operator">!</span>online <span class="token operator">&&</span> <span class="token operator"><</span>p<span class="token operator">></span>You're Offline<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator"><</span>img src<span class="token operator">=</span><span class="token punctuation">{</span>logo<span class="token punctuation">}</span> className<span class="token operator">=</span><span class="token string">"App-logo"</span> alt<span class="token operator">=</span><span class="token string">"logo"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>p<span class="token operator">></span> Edit <span class="token operator"><</span>code<span class="token operator">></span>src<span class="token operator">/</span>App<span class="token punctuation">.</span>js<span class="token operator"><</span><span class="token operator">/</span>code<span class="token operator">></span> and save to reload<span class="token punctuation">.</span> <span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator"><</span>a className<span class="token operator">=</span><span class="token string">"App-link"</span> href<span class="token operator">=</span><span class="token string">"https://reactjs.org"</span> target<span class="token operator">=</span><span class="token string">"_blank"</span> rel<span class="token operator">=</span><span class="token string">"noopener noreferrer"</span> <span class="token operator">></span> Learn React <span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>header<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Notice the line we added:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><span class="token operator">!</span>online <span class="token operator">&&</span> <span class="token operator"><</span>p<span class="token operator">></span>You're Offline<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">}</span></code></pre></div><p>When <code class="language-text">online</code> is false, it means that the user is offline so we're showing them the message. Remember that the logic behind changing the state based on the user's connectivity is actually done inside <code class="language-text">useOnline</code>. We just have to use the returned <code class="language-text">online</code> value and everything else is done inside the custom hook.</p><p>Let's now start the development server by running:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">npm start</code></pre></div><p>It will just be the default React page that we see everytime we start a new <code class="language-text">create-react-app</code> project:</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/react-1.png" class="kg-image" alt="React Custom Hooks Tutorial - Creating useOnline, Testing and Publishing It" loading="lazy"/></figure><p>The best way to test <code class="language-text">useOnline</code> by simulating going offline. To do that, open the devtools then go to the Application tab</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/react-2.png" class="kg-image" alt="React Custom Hooks Tutorial - Creating useOnline, Testing and Publishing It" loading="lazy"/></figure><p>As you can see there's a checkbox to simulate an offline browser. This is used for testing service workers but it will still work for any kind of testing regarding the user's connectivity.</p><p>Once you check the Offline checkbox, you should see the "You're Offline" message we added:</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/react-3.png" class="kg-image" alt="React Custom Hooks Tutorial - Creating useOnline, Testing and Publishing It" loading="lazy"/></figure><p>Our custom hook works! Try turning it on and off. When you check the Offline checkbox, the message will show. When you check it off, the message will be removed.</p><hr><h3 id="publishing-your-custom-hook">Publishing Your Custom Hook</h3><p>Now that we're done testing our custom hook, and we configured everything in our package, we are ready to publish it on NPM.</p><p>First, make sure you have an account on <a href="https://www.npmjs.com/">NPM</a>. If you don't, you need to create one first.</p><p>In your terminal run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> login</code></pre></div><p>You'll have to enter your username, password, and email. If it's all correct, you will be authenticated and authorized to publish your package.</p><p>In the root directory of your package, run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> publish</code></pre></div><p>Unless any errors occur, that's all you'll have to do! Your package will be live once this command is done running.</p><p>If you get an error regarding an existing package with a similar name, make sure to rename your package inside <code class="language-text">package.json</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"NEW_PACKAGE_NAME"</span></code></pre></div><p>Then try again.</p><p>If your package was published successfully, you will receive an email to notify you about it and you can go ahead and view it on NPM. You can then inside your project run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> PACKAGE_NAME</code></pre></div><p>And it will be installed just like any package out there!</p><p><strong>Updating Your Package</strong></p><p>If you later on decided to fix some bugs or make any changes in your package and you want to update it, just run in the root directory of the package:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm version TYPE</code></pre></div><p>Where TYPE can either be <code class="language-text">patch</code> (for small bug fixes), <code class="language-text">minor</code> (for small changes), and <code class="language-text">major</code> for big changes. You can read more about it <a href="https://docs.npmjs.com/about-semantic-versioning">here</a>.</p></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[All The Ways You Can Loop Arrays in Javascript]]></title><description><![CDATA[Here are different approaches to loop through an array in Javascript.]]></description><link>https://blog.shahednasser.com/all-the-ways-you-can-loop-arrays-in-javascript/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e9d</guid><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 06 Apr 2021 10:31:26 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/db87609c51a7bf1b6c1cb355821bf592/photo-1416269223193-bc45028133f5.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/db87609c51a7bf1b6c1cb355821bf592/photo-1416269223193-bc45028133f5.jpg" alt="All The Ways You Can Loop Arrays in Javascript"/><p>Whenever you want to loop through an array in Javascript, the common approach taken is using the <code class="language-text">for</code>, <code class="language-text">while</code>, or any of the similar loops. Although this is a valid choice, there are many other approaches that you can take to loop through an array in Javascript.</p><hr><h3 id="foreach">forEach</h3><p><code class="language-text">forEach</code> allows you to loop through all items in an array. For example, a for loop like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>will become:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">arr<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This eliminates the need to keep using the index to access the item, especially when the items in the array are objects and accessing their properties can become a hassle while using the index (unless you assign it to a new variable in the loop.)</p><p>You can also access the index as well:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">arr<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>item<span class="token punctuation">,</span> index<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><hr><h3 id="map-function map() { [native code] }1">map</h3><p><code class="language-text">map</code> loops through an array, and returns a new array. This is helpful when you are looping through an array, but also are modifying it.</p><p>For example, to do this in a for loop:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Can be done this way in map:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">arr <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> item <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>You can also assign it to a new array:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> newArr <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> item <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>You can access the index as well:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> newArr <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> item <span class="token operator">+</span> index<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><hr><h3 id="reduce-function reduce() { [native code] }1">reduce</h3><p><code class="language-text">reduce</code> allows you to loop through an array and accumulate the result from previous iterations up to the current iteration. In the end, a single result is added.</p><p>For example, let's say you want to get the sum of elements in an array. Using for loop you can do it like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">let</span> sum <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span> sum <span class="token operator">+=</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token punctuation">}</span></code></pre></div><p>Using <code class="language-text">reduce</code>, you can do it this way:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">const</span> sum <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">accumulator<span class="token punctuation">,</span> currentValue</span><span class="token punctuation">)</span> <span class="token operator">=></span> accumulator <span class="token operator">+</span> currentValue<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>The <code class="language-text">accumulator</code> parameter is the result after the last iteration before the current one, and its value, in the end, will be the value returned. By default, its initial value is the value of the first element and the iteration starts from the second element. So, in the example above, in the first iteration <code class="language-text">accumulator</code> will be 1 and <code class="language-text">currentValue</code> will be 2. 1 + 2 is 3 so in the second iteration <code class="language-text">accumulator</code> will be 3 and <code class="language-text">currentValue</code> will be 3 (since it's the item in the array that is after 2), and so on. In the end, the returned value will be 10.</p><p>You can also pass <code class="language-text">initialValue</code> to set the initial value to be different than the first element. If <code class="language-text">initialValue</code> is provided, the iteration will start from the first element. Passing <code class="language-text">initialValue</code> is also helpful if you're not sure if there are items in your array, as <code class="language-text">reduce</code> throws an error if the array is empty and no <code class="language-text">initialValue</code> is supplied.</p><p>An example of using <code class="language-text">initialValue</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">const</span> sum <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">accumulator<span class="token punctuation">,</span> currentValue</span><span class="token punctuation">)</span> <span class="token operator">=></span> accumulator <span class="token operator">+</span> currentValue<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>with <code class="language-text">initialValue</code> set to 0, in the first iteration <code class="language-text">accumulator</code> will be 0 and <code class="language-text">currentValue</code> will be 1 (starting from the first element in the array).</p><hr><h3 id="every-function every() { [native code] }1">every</h3><p><code class="language-text">every</code> allows you to loop through an array and check if all the items in the array return true in the callback function provided. This is helpful when you are looping through an array to make sure it's valid for a certain validation process. The loop will stop and return false whenever it encounters an item that does not return true in the callback function.</p><p>For example, to test that all the items in the array are greater than 0, you can do it like this with <code class="language-text">for</code> loop:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">let</span> allGreater <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> allGreater <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>allGreater<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>To do this using <code class="language-text">every</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> allGreater <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">every</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> item <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>allGreater<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>It will test that each <code class="language-text">item</code> is <code class="language-text">> 0</code> and if one of the items isn't, it will stop the loop and return false.</p><p>If you don't need to actually store the value in a variable like in the example above, you can just:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>arr<span class="token punctuation">.</span><span class="token function">every</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> item <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>You can also pass the <code class="language-text">index</code> as a second parameter with <code class="language-text">item</code>.</p><hr><h3 id="some-function some() { [native code] }1">some</h3><p>Unlike <code class="language-text">every</code>, <code class="language-text">some</code> allows you to loop through an array and check if at least one item returns true for the callback function. Once an item is found that passes the test provided, the loop will stop and return true. If no item is found that passes the test provided, the loop will return false.</p><p>For example, to check that at least one item is greater than 0 in the array using for loop:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">let</span> hasGreater <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> hasGreater <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>hasGreater<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>To do this using <code class="language-text">some</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> hasGreater <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">some</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> item <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>hasGreater<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>You can also eliminate assigning it to a variable if you don't need it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>arr<span class="token punctuation">.</span><span class="token function">some</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> item <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>You can access the index by passing it as a second parameter to the callback function.</p><hr><h3 id="filter-function filter() { [native code] }1">filter</h3><p><code class="language-text">filter</code> loops through an array and returns a new array with only the elements that return <code class="language-text">true</code> in the callback function.</p><p>For example, to get only the elements that are greater than zero in the array, you can do it this way with for loop: </p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> greaterArr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">{</span> greaterArr<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>greaterArr<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>To do this using <code class="language-text">fitler</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> greaterArr <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> item <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>greaterArr<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>You can also access the index by passing a second argument to the callback array.</p><hr><h3 id="find-function find() { [native code] }1">find</h3><p>With <code class="language-text">find</code> you can loop through an array to find the first element that returns true for a certain function. Once the element is found, the loop will stop and the element will be returned. If no element is found that satisfies the validation, <code class="language-text">undefined</code> will be returned. This is similar to <code class="language-text">some</code>, except that <code class="language-text">find</code> returns the element whereas <code class="language-text">some</code> just returns a boolean.</p><p>For example, to find an element in the array that is greater than 0 using for loop:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">let</span> greaterThan <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">{</span> greaterThan <span class="token operator">=</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>greaterThan<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>To do this using <code class="language-text">find</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> greaterThan <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> item <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>greaterThan<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>You can also access the index by passing a second argument to the callback array.</p><hr><h3 id="findindex">findIndex</h3><p>This is similar to <code class="language-text">find</code>, except that it returns the index of the element. If no element is found, it returns -1.</p><p>For example, to find the index of an element in the array that is greater than 0 using for loop:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">let</span> greaterThan <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">{</span> greaterThan <span class="token operator">=</span> i<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>greaterThan<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Using <code class="language-text">findIndex</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> greaterThan <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">findIndex</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> item <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>greaterThan<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>You can also access the index by passing a second argument to the callback array.</p><hr><h3 id="browser-compatibility">Browser Compatibility</h3><p>It should be noted that all of these functions are compatible with modern browsers, however, its compatibility in IE starts from IE9. So, if you need to make your code compatible with older browsers, you'll probably need to use a Polyfill.</p></hr></hr></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Git Basics Simply Explained For Beginners]]></title><description><![CDATA[Learning Git is very important for every developer. And for many beginners, it can be very confusing, as well.]]></description><link>https://blog.shahednasser.com/git-basics-for-beginners/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e9c</guid><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Fri, 02 Apr 2021 09:31:20 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/886dbe3bdf7a7567b6d417dc0f63e95f/photo-1556075798-4825dfaaf498.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/886dbe3bdf7a7567b6d417dc0f63e95f/photo-1556075798-4825dfaaf498.jpg" alt="Git Basics Simply Explained For Beginners"/><p>Learning Git is very important for every developer. And for many beginners, it can be very confusing, as well.</p><p>In this article, I'll go over the basic Git commands you'll need to know as a beginner in a simple manner.</p><hr><h3 id="cloning-a-repository">Cloning a Repository</h3><p>This one is simple in itself. You just created a repository and you want to clone it on your machine. Just run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">git</span> clone <span class="token operator"><</span>REPOSITORY_GIT_URL<span class="token operator">></span></code></pre></div><hr><h3 id="adding-a-repository-into-an-existing-project">Adding a Repository Into an Existing Project</h3><p>Let's say you already are working on a project and decided later on to create a repository for it. How do you add the repository to it?</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git init git add . git commit -m "Initial Commit" git remote add origin <REPOSITORY_GIT_URL> </code></pre></div><p>If the repository you are adding is empty, you can just run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git push origin master</code></pre></div><p>If, however, the repository has some files in it, I suggest you run this first:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git pull origin master</code></pre></div><p>Then run the <code class="language-text">push</code> command.</p><hr><h3 id="get-changes-from-repository">Get Changes from Repository</h3><p>To get changes from a repository:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git pull origin master</code></pre></div><hr><h3 id="undo-add-command">Undo Add Command</h3><p>If you ran:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git add <files></code></pre></div><p>or</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git add .</code></pre></div><p>then you realized that you made a mistake and you don't want to actually add those files, just run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git reset <files></code></pre></div><p>This will undo adding specific <code class="language-text">files</code>. If you want to undo adding all files:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git reset</code></pre></div><hr><h3 id="undo-latest-commit">Undo Latest Commit</h3><p>You made a commit, then realized something is wrong with it. To undo it, simply run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git reset ~HEAD</code></pre></div><p>You can also run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git revert HEAD</code></pre></div><p>The difference is that <code class="language-text">git revert</code> will add a new commit that reverts the latest commit. It's probably more helpful if you've pushed the commit that you want to undo.</p><hr><h3 id="edit-latest-commit">Edit Latest Commit</h3><p>To edit the last commit or the last commit message, run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git commit --amend -m "new message"</code></pre></div><hr><h3 id="remove-local-changes">Remove Local Changes</h3><p>If you made changes locally and you don't want them anymore for one reason or another, you can revert them back to their latest version in your Git Repository by running:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git checkout .</code></pre></div><p>To remove local changes of specific files instead of all changes you can run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git checkout <files></code></pre></div><hr><h3 id="create-a-branch">Create a Branch</h3><p>To create a new branch:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git branch <NEW_BRANCH></code></pre></div><hr><h3 id="switch-branches">Switch Branches</h3><p>To switch from one branch to another:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git checkout <BRANCH_NAME></code></pre></div><hr><h3 id="create-a-new-branch-and-switch-to-it">Create a New Branch And Switch To It</h3><p>To create a new branch and switch to it immediately, you can run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git checkout -b <BRANCH_NAME></code></pre></div><hr><h3 id="delete-a-branch">Delete a Branch</h3><p>To delete a branch:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git branch -d <BRANCH_NAME></code></pre></div><hr><h3 id="merge-branches">Merge Branches</h3><p>To merge a branch to another, switch to the branch you want to merge to then run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git merge <BRANCH_NAME></code></pre></div><hr><h3 id="stash-your-local-changes">"Stash" Your Local Changes</h3><p>Sometimes you might have changes locally, but you are not ready to commit them. If you need to work on something else in the meantime, go back to the original state of the repository, or change branches without losing changes, you can "stash" those changes for later:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git stash</code></pre></div><p>Then, when you want to pull out those changes again, just run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git stash pop</code></pre></div><p>Running this command will apply the latest changes you put in the stash and then remove it from the stash.</p><p>If you have a lot of changes that you've "stashed", you can check them by running:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git stash list</code></pre></div><p>Then, you can apply a stash from the list:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git stash apply <STASH_NAME></code></pre></div><hr><h3 id="set-your-email-and-name-in-the-configurations">Set Your Email and Name In The Configurations</h3><p>You can do this on a global scope and on a repository's scope. These commands will work on a global scope just by adding the <code class="language-text">--global</code> option.</p><p>To set the email:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git config user.email "YOUR_EMAIL"</code></pre></div><p>To set the name:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git config user.name "YOUR_NAME"</code></pre></div><hr><h3 id="remove-files-from-a-git-repository">Remove Files From a Git Repository</h3><p>To remove files from a Git Repository:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git rm <files></code></pre></div><p>To remove those files only from Git without removing them locally:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">git rm --cached <files></code></pre></div><p>To remove directories just add the <code class="language-text">-r</code> option.</p></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Stop Using Float in CSS - Here Are Your Alternatives]]></title><description><![CDATA[Here are a few options you should use instead of resorting to float in CSS.]]></description><link>https://blog.shahednasser.com/stop-using-float-in-css-here-are-your-alternatives/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e9b</guid><category><![CDATA[CSS]]></category><category><![CDATA[Tips]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 31 Mar 2021 07:19:09 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/91be082b36669d5601926d4548d7e8bb/photo-1546617885-4822125f891e.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/91be082b36669d5601926d4548d7e8bb/photo-1546617885-4822125f891e.jpg" alt="Stop Using Float in CSS - Here Are Your Alternatives"/><p>Throughout my years of working in CSS, the property that causes the biggest mess in the layout is <code class="language-text">float</code>. Whenever <code class="language-text">float</code> is used, unexpected behavior occurs at some point in your layout and design. I've also seen a few beginners who stumbled upon issues like this. They use float then when problems arise, they find it hard to link it back to the floated element.</p><p>For this reason, I'm giving you a few options you can use to achieve the same effect you need with <code class="language-text">float</code> while avoiding the mess. These options target <code class="language-text">block</code> elements, as for <code class="language-text">inline</code> elements I assume you know you can use <code class="language-text">text-align</code> with. </p><hr><h3 id="margin">Margin</h3><p>You've probably used <code class="language-text">margin: 0 auto;</code> a lot to center a block element horizontally. You can also use <code class="language-text">margin</code> to align a block element to the left or to the right. If you need to align it to the left, then set <code class="language-text">margin-right: auto</code> and <code class="language-text">margin-left: 0;</code>. If you need to align it to the right, then set <code class="language-text">margin-left: auto</code> and <code class="language-text">margin-right: 0;</code>. Basically, to align a block element to one side horizontally, set the margin of that side to 0 and the opposite side to auto.</p><p>It should be noted that the block should have a width set less than a <code class="language-text">100%</code>. So it should either have a fixed width value or <code class="language-text">fit-content</code>.</p><!--kg-card-begin: html--><p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="css,result" data-user="shahednasser" data-slug-hash="ExZNMgv" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Align with Margin"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/ExZNMgv"> Align with Margin</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>As you can tell, you can't really align two elements on the same level with this method. You should try one of the other methods detailed below.</p><hr><h3 id="align-with-flex">Align with Flex</h3><p>Using flex, you can align your elements even more flexibly. In particular, to align your element horizontally to the left or to the right, first, you need to add <code class="language-text">display: flex;</code> to the parent. Then, you have two options depending on the <code class="language-text">flex-direction</code> you will use. If you use <code class="language-text">flex-direction: row;</code> then set <code class="language-text">justify-content: flex-end;</code> to align the item to the end of the parent element or <code class="language-text">justify-content: flex-start;</code> to align the item to the beginning of the parent element. This also allows you to apply a similar style for both right-to-left and left-to-right layout, as <code class="language-text">flex-end</code> in left-to-right will align the element to the right and <code class="language-text">flex-start</code> will align the element to the left, whereas in right-to-left it will be the opposite.</p><!--kg-card-begin: html--><p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="css,result" data-user="shahednasser" data-slug-hash="BapQbRX" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Align with Flex"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/BapQbRX"> Align with Flex</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>To align the element with another element on the same level, you can use a combination of flex and margin like explained above:</p><!--kg-card-begin: html--><p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="KKaNERg" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Align with Flex"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/KKaNERg"> Align with Flex</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><hr><h3 id="align-with-grid">Align with Grid</h3><p>Now, this one may be more complex depending on your use case, but you can also align blocks using grids. What you need to do is set the display of the parent element to <code class="language-text">grid</code>, then, in the case of one block in the grid that you just want to align to the right, you can set <code class="language-text">grid-auto-columns: calc(100% - BLOCK_WIDTH);</code> if you have the block width set. If not then this won't be necessary. Then, set <code class="language-text">grid-area: right;</code> on the block you want to align and it will be aligned to the right.</p><p>Of course, you can do much more with grids and you can use them for many blocks with different kinds of alignments, this is just a simple case of aligning an element in the grid to the right.</p><!--kg-card-begin: html--><p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="css,result" data-user="shahednasser" data-slug-hash="zYNobPE" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Align with Grid"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/zYNobPE"> Align with Grid</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>To align two blocks on the same level, you can make use of <code class="language-text">grid-template-areas</code> to specify the template of the grid and the name of each area, then assign your blocks the area they should be in</p><!--kg-card-begin: html--><p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="rNjWRgJ" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Align with Grid"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/rNjWRgJ"> Align with Grid</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><hr><h3 id="conclusion">Conclusion</h3><p>There also may be other options that you can go for when aligning your elements depending on your layout. Regardless of which option you choose, stop using float.</p></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[I Created a CLI to Cross-Post Your Articles On Dev, Hashnode, and Medium]]></title><description><![CDATA[If you own a blog like me, but also cross-post your articles on other platforms, it gets tedious. So I created a simple CLI to do it easily.]]></description><link>https://blog.shahednasser.com/i-created-a-cli-to-cross-post-your-articles-on-dev-hashnode-and-medium/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e9a</guid><category><![CDATA[Open Source]]></category><category><![CDATA[My Experience]]></category><category><![CDATA[Projects]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Fri, 26 Mar 2021 21:32:49 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/8aed5b6ee3f2e7aeb2f33a45ecfe6595/photo-1567361808960-dec9cb578182.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/8aed5b6ee3f2e7aeb2f33a45ecfe6595/photo-1567361808960-dec9cb578182.jpg" alt="I Created a CLI to Cross-Post Your Articles On Dev, Hashnode, and Medium"/><p>If you own a blog like me, but also cross-post your articles on platforms like Dev, Hashnode, and Medium, it gets tedious to post your articles in different places.</p><p>So, I created a simple CLI to cross-post my articles on these platforms easily. You can find it on <a href="https://www.npmjs.com/package/cross-post-blog">NPM</a> and check the code on <a href="https://github.com/shahednasser/cross-post#readme">GitHub</a>.</p><hr><h2 id="installation">Installation</h2><p>In your terminal:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm i -g cross-post-blog </code></pre></div><hr><h2 id="usage">Usage</h2><h3 id="set-configuration">Set Configuration</h3><p>For the simplicity of the CLI, and considering most of the APIs of each of the platforms do not allow or provide endpoints for user authentication, you will need to get your access tokens, API keys, or integration tokens from your own profile before using cross-post. This will just need to be done the first time or if you want to change the tokens.</p><p><strong>The tokens are all stored on your local machine.</strong></p><p>Here's a guide on how to do this for each of the platforms:</p><h3 id="dev-to">dev.to</h3><p>After logging into your account on dev.to, click on your profile image and then click on Settings</p><figure class="kg-card kg-image-card"><img src="https://github.com/shahednasser/cross-post/raw/master/assets/dev-1.png" class="kg-image" alt="I Created a CLI to Cross-Post Your Articles On Dev, Hashnode, and Medium" loading="lazy"/></figure><p>Then, click on the Accounts tab in the sidebar</p><figure class="kg-card kg-image-card"><img src="https://github.com/shahednasser/cross-post/raw/master/assets/dev-2.png" class="kg-image" alt="I Created a CLI to Cross-Post Your Articles On Dev, Hashnode, and Medium" loading="lazy"/></figure><p>Scroll down to the "DEV Community API Keys" section. You need to generate a new key. Enter "Cross Post" in the description text box or any name you want then click "Generate API key"</p><figure class="kg-card kg-image-card"><img src="https://github.com/shahednasser/cross-post/raw/master/assets/dev-3.png" class="kg-image" alt="I Created a CLI to Cross-Post Your Articles On Dev, Hashnode, and Medium" loading="lazy"/></figure><p>Copy the generated API key, then in your terminal:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">cross-post config dev </code></pre></div><p>You'll be prompted to enter the API key. Paste the API key you copied earlier and hit enter. The API key will be saved.</p><h3 id="hashnode">Hashnode</h3><p>After logging into your account on Hashnode, click on your profile image and then click on "Account Settings"</p><figure class="kg-card kg-image-card"><img src="https://github.com/shahednasser/cross-post/raw/master/assets/Hashnode-1.png" class="kg-image" alt="I Created a CLI to Cross-Post Your Articles On Dev, Hashnode, and Medium" loading="lazy"/></figure><p>In the sidebar click on "Developer"</p><figure class="kg-card kg-image-card"><img src="https://github.com/shahednasser/cross-post/raw/master/assets/Hashnode-2.png" class="kg-image" alt="I Created a CLI to Cross-Post Your Articles On Dev, Hashnode, and Medium" loading="lazy"/></figure><p>Click the "Generate" button and then copy the generated access token.</p><figure class="kg-card kg-image-card"><img src="https://github.com/shahednasser/cross-post/raw/master/assets/Hashnode-3.png" class="kg-image" alt="I Created a CLI to Cross-Post Your Articles On Dev, Hashnode, and Medium" loading="lazy"/></figure><p>Run the following in your terminal:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">cross-post config hashnode </code></pre></div><p>First, you'll be prompted to enter your access token. Then, you need to enter your Hashnode username. The reason behind that is that when later posting on hashnode your publication id is required, so your username will be used here to retrieve the publication id. Once you do and everything goes well, the configuration will be saved successfully.</p><h3 id="medium">Medium</h3><p>After logging into Medium, click on your profile image and then click on "Settings"</p><figure class="kg-card kg-image-card"><img src="https://github.com/shahednasser/cross-post/raw/master/assets/Medium-1.png" class="kg-image" alt="I Created a CLI to Cross-Post Your Articles On Dev, Hashnode, and Medium" loading="lazy"/></figure><p>Then click on "Integration Tokens" in the sidebar</p><figure class="kg-card kg-image-card"><img src="https://github.com/shahednasser/cross-post/raw/master/assets/Medium-2.png" class="kg-image" alt="I Created a CLI to Cross-Post Your Articles On Dev, Hashnode, and Medium" loading="lazy"/></figure><p>You have to enter the description of the token then click "Get integration token" and copy the generated token.</p><figure class="kg-card kg-image-card"><img src="https://github.com/shahednasser/cross-post/raw/master/assets/Medium-3.png" class="kg-image" alt="I Created a CLI to Cross-Post Your Articles On Dev, Hashnode, and Medium" loading="lazy"/></figure><p>In your terminal run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">cross-post config medium </code></pre></div><p>Then enter the integration token you copied. A request will also be sent to Medium to get your authorId as it will be used later to post your article on Medium. Once that is done successfully, your configuration will be saved.</p><hr><h3 id="cross-posting-your-articles">Cross-Posting Your Articles</h3><p>To cross-post your articles, you will use the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">cross-post run <url> [options] </code></pre></div><p>Where <code class="language-text">url</code> is the URL of your article that you want to cross-post. <code class="language-text">options</code> can be:</p><ol><li><code class="language-text">-p, --platforms [platforms...]</code> The platform(s) you want to post the article on. By default, if this option is not included, it will be posted on all the platforms. An example of its usage:</li></ol><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">cross-post run <url> -p dev hashnode </code></pre></div><ol><li><code class="language-text">-t, --title [title]</code> The title by default will be taken from the URL you supplied, however, if you want to use a different title you can supply it in this option.</li><li><code class="language-text">-s, --selector [selector]</code> by default, the <code class="language-text">article</code> selector will be used to find your article in the URL you pass as an argument. However, if you need a different selector to be used to find the article, you can pass it here.</li></ol><p>This command will find the HTML element in the URL page you pass as an argument and if found, it will extract the title (if no title is passed in the arguments) and cover the image.</p><p>It should be noted that on all platforms the article will be posted as a draft, however, due to the limitations of the Hashnode API, it will be posted as "hidden from Hashnode" but it will be public in your publication.</p><p><strong>UPDATE:</strong> In the latest version of this library, you can now pass the option <code class="language-text">-pu, --public</code> to publish the article publicly.</p><hr><h3 id="conclusion">Conclusion</h3><p>If you find any bugs or have any ideas you would like to contribute, please do so on the issues tab in the <a href="https://github.com/shahednasser/cross-post">GitHub Repository</a>!</p></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Tips For Beginner Maintainers of Open Source Projects]]></title><description><![CDATA[As an open-source project maintainer, I have learned a thing or two along the way. This article will hopefully help new or beginner maintainers.]]></description><link>https://blog.shahednasser.com/tips-for-beginner-maintainers-of-open-source-projects/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e99</guid><category><![CDATA[Open Source]]></category><category><![CDATA[Tips]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 24 Mar 2021 09:40:44 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/6fa5d542181b6a4e457cdfd8e4f81e4e/photo-1593642532454-e138e28a63f4.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/6fa5d542181b6a4e457cdfd8e4f81e4e/photo-1593642532454-e138e28a63f4.jpg" alt="Tips For Beginner Maintainers of Open Source Projects"/><p>Not long ago I wrote an article about <a href="https://blog.shahednasser.com/tips-for-beginners-to-open-source/">tips for beginners to open source</a>. It was to help some confusions beginners have when they contribute to open source projects. In this article, I will try to give out some tips for maintainers of open source projects.</p><p>I personally have been <a href="https://blog.shahednasser.com/how-i-learned-about-contributing-to-open-source-projects-by-creating-one/">maintaining a couple of open source projects</a> and I have learned a thing or two along the way, so I'm writing this in the hopes that it will help new or beginner maintainers. This is a general overview of being a maintainer regardless of the programming language, concept or type of open source project you are maintaining.</p><hr><h3 id="make-your-contributing-guidelines-as-clear-as-possible">Make Your Contributing Guidelines As Clear As Possible</h3><p>When contributors want to help out in your project, it's gonna take them some time to look around and understand the structure and environment you have in your project. To avoid confusion and assumptions, and to make sure that a unified code convention is being used, you need to create a CONTRIBUTING.md file in your repository that will hold all the contributing guidelines needed for anyone to make a contribution. This will also help beginner contributors understand more clearly the steps they need to take to make a successful contribution. </p><p>Whether you need to add lines of code needed to set up the project, images, or any instructions necessary to understand how to contribute correctly, make sure it's all detailed and clear. If your project consists of multiple parts, make sure to split the contributing guidelines into two parts detailing how to contribute to each of them.</p><hr><h3 id="create-issue-and-pull-request-templates">Create Issue and Pull Request Templates</h3><p>As a maintainer, you can create templates for issues and pull requests. This will help anyone that's submitting an issue or PR to understand how they should explain what issue they are presenting or resolving. This will also help you understand the process of checking issues and PRs and make it unified to save you time.</p><p>What you should do is that you should create templates for the different types of issues you have or for the pull requests that will hold comments that will not be seen in the issue but will be seen by the contributors when creating it. It could be something like:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="markdown"><pre class="language-markdown"><code class="language-markdown"><span class="token comment"><!-- Please read the contribution guide before contributing https://github.com/sButtons/sbuttons/blob/master/CONTRIBUTING.md --></span> <span class="token comment"><!-- Please describe what changes or additions this pull request pertain to --></span> <span class="token comment"><!-- Specify the issue it relates to, if any ---></span></code></pre></div><p>Issue templates reside in your repository under <code class="language-text">.github/ISSUE_TEMPLATE</code> whereas pull request template resides in <code class="language-text">pull_request_template.md</code>. GitHub also can guide you through creating them, making it easier for you.</p><hr><h3 id="welcome-beginners">Welcome Beginners</h3><p>Beginners to open source are always very intimidated and not sure how to start contributing (I know that because that's how I was like, too). That's why it's very important to make sure your project welcomes beginners to contribute. This means that you should always leave some easy tasks and issues for beginners to take on. I suggest adding and making use of labels in your repository likes <code class="language-text">first-timers-only</code>, <code class="language-text">up-for-grabs</code>, <code class="language-text">good-first-issue</code> and <code class="language-text">help-wanted</code>. Also, when assigning the issue make sure that any issue labeled with <code class="language-text">first-timers-only</code> are actually done by beginners.</p><p>Another thing you should do is to make sure to be patient and comprehensive with beginners. Take the time to instruct them how to finish a certain task. If you have a team of maintainers or reviewers in your project, make sure they do that as well.</p><p>In my own experience, helping beginners contribute to my projects leads to them suggesting new ideas and making more contributions with time. So, don't look over making your repository a safe space for them, even if it's just for parts of it.</p><hr><h3 id="use-all-contributors">Use <a href="https://allcontributors.org/">All Contributors</a></h3><p>This one isn't a necessity, but for me, I like adding it in some of my projects, especially those that have a lot of contributors. <a href="https://allcontributors.org/">All Contributors</a> is a bot that helps you make your contributors feel recognized, and not necessarily just those who have contributed code to your project. Using their <a href="https://allcontributors.org/docs/en/emoji-key">emoji keys</a> to indicate the contribution type, you can recognize each contributor for the contribution they've made. It helps make contributors feel appreciated for their effort. It can add the contributors in a table in your README file by default, or another file in your repository that you can specify in the configuration. Take a look at an example of <a href="https://github.com/sButtons/sbuttons/blob/master/CONTRIBUTORS.md">how it will look like</a>.</p><p>An example of how it works is just leaving a comment on an issue or pull request like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">@all-contributors please add @shahednasser for design</code></pre></div><p>This will add user @shahednasser as a contributor for design. This also helps in making contributors that don't necessarily contribute code feel recognized. For example, if someone suggests an idea, you can add them as a contributor for idea.</p><hr><h3 id="make-use-of-actions">Make Use Of Actions</h3><p>GitHub Actions can be very helpful in automating certain parts of your project. A simple example of a GitHub action is an action that uses <a href="https://prettier.io/">prettier</a> every time changes are made to the code in the repository. This maintains the same formatting of the code, regardless of who contributes. This is actually very important as a lot of formatting issues start happening as you get more contributors. You can also add actions for compilations, automatic comments, and much more. Anything that can be automated and will help make the repository clean and structured or will help contributors make their contributions easier, try to make it a GitHub Action.</p><hr><h3 id="add-code-scanning-and-dependabot">Add Code Scanning and Dependabot</h3><p>This depends on your type of project, but on GitHub, you can add Code Scanning that will scan your code based on the programming language used and make sure no vulnerabilities or security issues are introduced. To turn Code Scanning on and add code scanners, you can do this under the Security tab in your repository. I also suggest turning on Dependabot so that you will get a warning about any vulnerabilities in your dependencies.</p><hr><h3 id="create-a-community">Create a Community</h3><p>One of the best parts about working on open source projects is the community you can create. Create a respective community. Make everyone feel welcome and appreciate every contribution you get. Create a healthy environment for anyone that wants to give back to the open source community. This will make your project a safe space and will attract more contributors to it, who will help make your project bigger and reach higher levels.</p></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Making Your Extension Compatible with Both Chrome and Firefox]]></title><description><![CDATA[This article helps you understand how to make your extension compatible with both Chrome and Firefox.]]></description><link>https://blog.shahednasser.com/making-your-extension-compatible-with-both-chrome-and-firefox/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e98</guid><category><![CDATA[Browser Extensions]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 23 Mar 2021 12:21:12 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/7f4d942a55ee75c983841369b2092689/photo-1504292004442-f285299403fa.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/7f4d942a55ee75c983841369b2092689/photo-1504292004442-f285299403fa.jpg" alt="Making Your Extension Compatible with Both Chrome and Firefox"/><p>Developing extensions for different browsers is mostly similar, however, there are a few differences you should look out for.</p><p>This article lists the difference between developing Chrome extensions and Firefox Add-Ons, helping you understand how to make sure your extension is compatible with both browsers. In the end I will also include the difference when packaging and publishing the extensions on the different platforms.</p><hr><h3 id="manifest">Manifest</h3><p>Here are the key differences in the <code class="language-text">manifest.json</code> file:</p><ol><li>Firefox has a <code class="language-text">developer</code> key in the manifest, which is an object that includes <code class="language-text">name</code> and <code class="language-text">url</code>. Chrome doesn't.</li><li>If you are using the Storage API and want to test your extension in your browser by loading it from your machine, Firefox requires the <code class="language-text">browser_specific_settings</code> key to work, otherwise the Storage API will not work. An example of it would be:</li></ol><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"browser_specific_settings"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"gecko"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"id"</span><span class="token operator">:</span> <span class="token string">"addon@example.com"</span><span class="token punctuation">,</span> <span class="token property">"strict_min_version"</span><span class="token operator">:</span> <span class="token string">"42.0"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><h3 id="manifest-v3">Manifest V3</h3><p>Currently, Chrome is pushing towards using Manifest V3 which has been controversial for a few reasons. As for Firefox in a <a href="https://blog.mozilla.org/addons/2019/09/03/mozillas-manifest-v3-faq/">blog post</a> in 2019, Mozilla indicated that they will also support Manifest V3, however, they're not obligated to implement every part of it. Mozilla is intending to keep a lot of functions and APIs that Chrome is discarding in V3.</p><p><em>Suggested Read: <a href="https://blog.shahednasser.com/chrome-extension-tutorial-migrating-to-manifest-v3-from-v2/">Learn how to migrate your Chrome extension from Manifest V2 to V3</a>!</em></p><hr><h3 id="api">API</h3><p>In Chrome, the API namespace is <code class="language-text">chrome.*</code>, whereas for Firefox it's <code class="language-text">browser.*</code>. Firefox claims that it supports <code class="language-text">chrome.*</code>, but it's preferred to use <code class="language-text">browser.*</code>.</p><p>The main difference between the two, however, is that <code class="language-text">chrome.*</code> only supports callbacks when handling asynchronous events, whereas <code class="language-text">browser.*</code> supports both callbacks and promises.</p><p><strong>Update</strong>: With the release of MV3, more and more APIs in Chrome <a href="https://developer.chrome.com/docs/extensions/mv3/intro/mv3-overview/#promises">now support Promises</a>, with full support coming soon. Callbacks will continue to be supported as well.</p><p>Here's an example of how you'd query tabs in Chrome:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript">chrome<span class="token punctuation">.</span>tabs<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">active</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">tabs</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>tabs<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>title<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>And here's the same example in Firefox when using Promises:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">browser.tabs.query({active: true}) .then ((tabs) => console.log(tabs[0].title)) .catch ((err) => console.error(err))</code></pre></div><p>Mozilla, however, offers a polyfill that allows you to use Promises in all browser extensions. You can check it out <a href="https://github.com/mozilla/webextension-polyfill/">here</a>.</p><hr><h3 id="functions-differences">Functions Differences</h3><p>Some functions have different signatures or behavior for each of the browsers:</p><ol><li>Chrome states in their <code class="language-text">chrome.notifications</code> <a href="https://developer.chrome.com/docs/extensions/reference/notifications/#type-NotificationOptions">API documentation</a> that for <code class="language-text">chrome.notifications.create</code> the parameter <code class="language-text">iconUrl</code> is required, whereas for Firefox <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/notifications/NotificationOptions">it's optional</a>.</li><li>For the <code class="language-text">tabs</code> API in the functions <code class="language-text">insertCSS</code> and <code class="language-text">executeScript</code>, Firefox resolves the URLs being passed relative to the current page, whereas Chrome resolves the URLs being passed as relative to the root of the extension. To resolve this, use <code class="language-text">chrome.runtime.getURL</code> (or replace <code class="language-text">chrome</code> with <code class="language-text">browser</code> for Firefox) to get the fully-qualified URL for a file in the extension.</li><li><code class="language-text">tabs.query</code> is not allowed in Firefox without the tabs permission in the <code class="language-text">manifest.json</code> but it's allowed in Chrome if the tab matches the host permissions in <code class="language-text">manifest.json</code>.</li><li>The <code class="language-text">declarativeContent</code> API that Chrome has is not yet implemented in Firefox.</li></ol><hr><h3 id="some-additional-differences">Some Additional Differences</h3><ol><li>URLs in CSS files in Firefox are resolved relative to the CSS file, whereas in Chrome they're resolved relative to the current page.</li><li>Firefox does not allow functions like <code class="language-text">alert</code>, <code class="language-text">confirm</code> or <code class="language-text">prompt</code> in background scripts.</li><li>Chrome allows passing relative URLs when making a request (for example, <code class="language-text">/user</code>), however, Firefox requires absolute URLs.</li></ol><hr><h3 id="packaging-and-publishing-extensions-experience">Packaging and Publishing Extensions Experience</h3><p>When packaging the extension to publish it, in Chrome the <code class="language-text">manifest.json</code> file should be in the root of the package. Whereas in Firefox the extension should be encapsulated in a directory that contains <code class="language-text">manifest.json</code> at the root of it.</p><p>Here's an example of how a Chrome extension package structure would look like:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">root | | |_ _ _ manifest.json</code></pre></div><p>And here's how it would look like in a Firefox extension package:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">root | | |_ _ _ my-extension | | |_ _ _ manifest.json</code></pre></div><p>When it comes to publishing your extension, Google requires a one time fee of $25 (at the time of writing this) to create a developer account. Once you do, you don't need to make any additional payments when adding more extensions. With Firefox, you don't need to pay anything to publish an extension.</p><p>Once you have a developer account on both platforms, you can upload your extension.</p><p>When uploading your extension on Chrome, you will be asked to enter a lot of information regarding the name of the extension, description, a variety of images in different sizes, and other information that the user will see when downloading your extension. You will also be required to enter a few details regarding privacy and handling user data based on the permissions you're asking for in <code class="language-text">manifest.json</code>. You also can enter a Google Analytics code that helps you track your extension and its users more thoroughly. Once you are done, the review process can take some time before your extension is published on the Chrome Webstore.</p><p>When uploading your extension on Firefox, you will be asked first to enter a few information regarding remote code execution, privacy and other security information as well. Then, you will get to enter almost the same information as for Chrome regarding the name, description, etc... However, Firefox requires less images and isn't as strict about the sizing as Chrome. Firefox does not allow adding a Google Analytics tracking code to track your extension. Once you're done, your extension will be published right away.</p><p>As for updating your extension, for Chrome you just need to upload the latest package, and if there are no changes in the permissions, you don't really need to enter any other information. If you have any changes in the permissions you might need to fill out more privacy and security related information. Once you're done, your extension will be reviewed and if it's approved it will be published.</p><p>For Firefox, when updating you will need to enter the same information as before regarding security and remote execution. You will also be asked to add Changelog information for your users to know what changed. Once you're done, your extension will be published right away.</p></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Simple Twitter Bot With Node.js Tutorial Part 3: Search and Retweet]]></title><description><![CDATA[Following parts 1 and 2, this tutorial will go over how to periodically search for specific keywords or hashtags in tweets and retweet them.]]></description><link>https://blog.shahednasser.com/simple-twitter-bot-tutorial-part-3-search-and-retweet/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e97</guid><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 20 Mar 2021 12:52:43 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/82c3e4e7257c081eecdc8e2cc498fbf7/photo-1525770041010-2a1233dd8152.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/82c3e4e7257c081eecdc8e2cc498fbf7/photo-1525770041010-2a1233dd8152.jpg" alt="Simple Twitter Bot With Node.js Tutorial Part 3: Search and Retweet"/><p><em>If you haven't read parts <a href="https://blog.shahednasser.com/simple-twitter-bot-tutorial-with-node-js/">1</a> and <a href="https://blog.shahednasser.com/simple-twitter-bot-tutorial-with-node-part-2/">2</a>, I suggest you do to understand part 3 a little better.</em></p><p>In the first two parts of this tutorial, we went over how to create a Twitter bot that sends out tweets from the <a href="https://history.muffinlabs.com/">Today in History</a> API and then created scheduled tasks that make sure these tweets are tweeted automatically at certain times of the day. We are using <a href="https://github.com/FeedHive/twitter-api-client">twitter-api-client</a> to easily connect to the Twitter API. You can see the bot for this tutorial in live action on <a href="https://twitter.com/HistoryBot7">@HistoryBot7</a>.</p><p> In this part of the tutorial, we'll go over searching tweets based on specific queries and retweeting them. You've probably seen a lot of bots do this. You tweet something with a hashtag or certain keywords, and a bot retweets it right away. This is what we will do. We will search for tweets that have the hashtag "#HistoryBot" every minute and retweet them.</p><p>You can follow up with the code for this tutorial on the <a href="https://github.com/shahednasser/history-bot">GitHub Repository</a>.</p><hr><h3 id="searching-tweets">Searching Tweets</h3><p>The first step is to search through the latest tweets that have the hashtag "#HistoryBot" so that we can later on retweet them.</p><p>We will create a new file at the root of the project called <code class="language-text">search.js</code>. The reason we are doing it in a separate file is that we will later need to run a scheduled command on this file independently.</p><p>The file should start by initializing the TwitterClient as such:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">//search.js</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'dotenv'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">{</span>TwitterClient<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'twitter-api-client'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> twitterClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TwitterClient</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">apiKey</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_API_KEY</span><span class="token punctuation">,</span> <span class="token literal-property property">apiSecret</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_API_SECRET</span><span class="token punctuation">,</span> <span class="token literal-property property">accessToken</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_ACCESS_TOKEN</span><span class="token punctuation">,</span> <span class="token literal-property property">accessTokenSecret</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_ACCESS_TOKEN_SECRET</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>If you've been following up with the tutorials, you'll notice that this is exactly the same in <code class="language-text">index.js</code>. So, instead of repeating the code. We will move this code into another file called <code class="language-text">init.js</code>, export <code class="language-text">twitterClient</code> in it, and then require it in our <code class="language-text">index.js</code> files and <code class="language-text">search.js</code> files. (If you are just following the tutorial for your own project, you don't need to do this step.)</p><p>So, now we will have <code class="language-text">init.js</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">//init.js</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'dotenv'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">{</span>TwitterClient<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'twitter-api-client'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> twitterClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TwitterClient</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">apiKey</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_API_KEY</span><span class="token punctuation">,</span> <span class="token literal-property property">apiSecret</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_API_SECRET</span><span class="token punctuation">,</span> <span class="token literal-property property">accessToken</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_ACCESS_TOKEN</span><span class="token punctuation">,</span> <span class="token literal-property property">accessTokenSecret</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_ACCESS_TOKEN_SECRET</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> twitterClient</code></pre></div><p>Then, we will require twitterClient in <code class="language-text">index.js</code> and remove the previous code initializing the Twitter Client:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">//index.js</span> <span class="token keyword">const</span> twitterClient <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./init'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> axios <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'axios'</span><span class="token punctuation">)</span> axios<span class="token punctuation">.</span>get<span class="token operator">...</span> <span class="token comment">//rest of the code from before</span></code></pre></div><p>And change <code class="language-text">search.js</code> as such:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">//search.js</span> <span class="token keyword">const</span> twitterClient <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./init'</span><span class="token punctuation">)</span></code></pre></div><p>This way, we are avoiding repeating the same code in different files.</p><p>Now back to our search script. After initializing the Twitter Client, we need to search tweets that have in them "#HistoryBot". To do so, we will use the method <code class="language-text">tweets.search</code> on <code class="language-text">twitterClient</code>. This method takes a variable number of parameters, for example, <code class="language-text">since_id</code> helps you get tweets after a specific tweet. This can help you optimize the search you are doing and the tweets you are retreiving. You can find a list of all their parameters <a href="https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets">here</a>.</p><p>For the basic usage of our example, we will pass it two parameters: <code class="language-text">q</code> which is the search query we are performing, which in the case of our tutorial is "#HistoryBot" but you can place any kind of keywords or hashtags in it that you want to find in a tweet. The second parameter is <code class="language-text">result_type</code> and the value will be <code class="language-text">recent</code>. This is to ensure that we are getting the most recent results, as the default value for this parameter is <code class="language-text">mixed</code> which retrieves a mix of recent tweets as well as popular tweets. We need to use <code class="language-text">recent</code> as our goal is to retweet tweets as they are tweeted.</p><p> By default, the endpoint this method calls retrieves a maximum of 15 tweets. You can change that if you want by passing the <code class="language-text">count</code> parameter, which can be 100 at most.</p><p>So, our code in <code class="language-text">search.js</code> will be as such:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> twitterClient <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./init'</span><span class="token punctuation">)</span> twitterClient<span class="token punctuation">.</span>tweets<span class="token punctuation">.</span><span class="token function">search</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">q</span><span class="token operator">:</span> <span class="token string">'#HistoryBot'</span><span class="token punctuation">,</span> <span class="token literal-property property">result_type</span><span class="token operator">:</span> <span class="token string">'recent'</span><span class="token punctuation">,</span> <span class="token comment">//get latest tweets with this hashtag</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre></div><p>This will retrieve the last 15 tweets that have the "#HistoryBot" in them, then will just print them to the console.</p><p>To test this, run the following command in your terminal:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">node</span> search.js</code></pre></div><p>If everything is done correctly, you will see an object containing <code class="language-text">status</code> attribute which has an array of statuses. Each status has attributes like <code class="language-text">id</code>, <code class="language-text">id_str</code>, <code class="language-text">text</code>, and many others as well. Keep in mind that there aren't many tweets with this hashtag (probably none), as I am using this hashtag to make sure the tutorial doesn't retweet anything random. So, you can replace the hashtag with anything else to see it in effect.</p><hr><h3 id="retweeting-tweets">Retweeting Tweets</h3><p>After searching tweets based on our query, we will want to retweet them into our bot. To do so, we will use the method <code class="language-text">tweets.statusesRetweetById</code> on <code class="language-text">twitterClient</code>. This method takes the parameter <code class="language-text">id</code>, which will be <code class="language-text">id_str</code> from the status object we received before. </p><p>It should be noted that if a tweet has been already tweeted, Twitter will ignore it. If you've hit a limit for retweeting, you'll receive an error with status code 403. You can read more about this endpoint <a href="https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/post-statuses-retweet-id">here</a>. </p><p>So, we will change our code in <code class="language-text">search.js</code> as such:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">//...</span> twitterClient<span class="token punctuation">.</span>tweets<span class="token punctuation">.</span><span class="token function">search</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">q</span><span class="token operator">:</span> <span class="token string">'#HistoryBot'</span><span class="token punctuation">,</span> <span class="token literal-property property">result_type</span><span class="token operator">:</span> <span class="token string">'recent'</span><span class="token punctuation">,</span> <span class="token comment">//get latest tweets with this hashtag</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>response<span class="token punctuation">.</span>statuses<span class="token punctuation">)</span> <span class="token punctuation">{</span> response<span class="token punctuation">.</span>statuses<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">status</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> twitterClient<span class="token punctuation">.</span>tweets<span class="token punctuation">.</span><span class="token function">statusesRetweetById</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> status<span class="token punctuation">.</span>id_str <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resp</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Retweeted tweet #</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>status<span class="token punctuation">.</span>id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre></div><p>Instead of printing the response from <code class="language-text">tweets.search</code> into our console, we are iterating over the <code class="language-text">statuses</code> array received in the response and retweeting each tweet using <code class="language-text">tweets.statusesRetweetById</code>, passing it <code class="language-text">id_str</code> of each of the statuses. If it's successful, it will print to the console <code class="language-text">Retweeted tweet #${status.id}</code> where <code class="language-text">status.id</code> is the id of the status. If it fails, it will print to the console the error received.</p><p>Now, let's test this again by running the same command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">node</span> search.js</code></pre></div><p>And you will see that it will retweet tweets with this hashtag. </p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/-1-Shahed-on-Twitter-Retweet-me-HistoryBot-Twitter.png" class="kg-image" alt="Simple Twitter Bot With Node.js Tutorial Part 3: Search and Retweet" loading="lazy"/></figure><p>Note: I've tweeted <a href="https://twitter.com/HistoryBot7/status/1373249880324501511">this tweet</a> on @HistoryBot7 so you can test it out as well if there aren't any tweets with the hashtag!</p><hr><h3 id="deploying-to-server">Deploying To Server</h3><p>If you've followed up with <a href="https://blog.shahednasser.com/simple-twitter-bot-tutorial-with-node-part-2/">part 2</a> of our tutorials, you've seen that we deployed the bot on <a href="https://www.alwaysdata.com/en/">alwaysdata</a>. We will now update the server with our updated code, so that we can after schedule a task to run every minute and execute <code class="language-text">search.js</code>.</p><p>First, update your GitHub repository that you are using on the server with the most recent changes:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">git</span> <span class="token function">add</span> <span class="token builtin class-name">.</span> <span class="token function">git</span> commit -m <span class="token string">"added retweet functionality"</span> <span class="token function">git</span> push origin master</code></pre></div><p>Then, connect to your server with SSH like we did in part 2 using your credentials.</p><p>Once connected, navigate to the directory that has the bot's code and pull from the GitHub repository:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> history-bot <span class="token function">git</span> pull origin master</code></pre></div><p>This will update the code on our server with the latest changes. </p><p>Now, let's create the scheduled task on our alwaysdata server. If you are using a different server, this is just an easy way to create a cron job. </p><p>In your alwaysdata admin dashboard, go to Scheduled tasks under Advanced in the sidebar. Then click "Add a scheduled task"</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/always-data-1.png" class="kg-image" alt="Simple Twitter Bot With Node.js Tutorial Part 3: Search and Retweet" loading="lazy"/></figure><p>In the form on the next page, choose "Execute the command" for "Type of task", then for "Value" type the command "node ~/history-bot/search.js". Make sure to replace the command based on your own server path and files.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/alwaysdata-2.png" class="kg-image" alt="Simple Twitter Bot With Node.js Tutorial Part 3: Search and Retweet" loading="lazy"/></figure><p>In the Environment section, choose your SSH user from the dropdown and enter in the Working Directory field <code class="language-text">/home/history-bot/history-bot</code>, where the first history-bot is the name of the app you've created on alwaysdata for the bot, and the second one is the directory we have history bot in. You can also choose to omit this, as our command already specifies the full path of <code class="language-text">search.js</code></p><p>In the Frequency section, choose "Every" and type 1 in the field to execute the command every minute. You can change that of course to whatever fits your use case.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/alwaysdata-3.png" class="kg-image" alt="Simple Twitter Bot With Node.js Tutorial Part 3: Search and Retweet" loading="lazy"/></figure><p>Once you're done click Submit. Then, go to Sites under Web in the sidebar and restart your app. Now, the script will execute every minute!</p><p>To test the history bot for this tutorial, just tweet something with #HistoryBot and it will retweet you!</p><p>Note that if your bot already retweeted some tweets throughout the tutorial, you will need to unretweet them to see it in effect now. </p><p>If the bot is not working properly, you can check out the logs on your server for more info. If you are using alwaysdata, you can find the logs under <code class="language-text">~/admin/logs/job/2021</code>.</p><hr><h3 id="conclusion">Conclusion</h3><p>Following these 3 tutorials, you should be able to create a bot that tweets periodically and search through Twitter based on a specific keyword or hashtag and retweet tweets, then deploy the bot. Hope you create something great with it!</p></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[I Recreated a Bootstrap Website with Tailwind CSS, And Here Are The Differences]]></title><description><![CDATA[I decided to recreate a website that was originally built with the help of Bootstrap. Here's the difference between working with Tailwind CSS and Bootstrap.]]></description><link>https://blog.shahednasser.com/i-recreated-a-bootstrap-website-with-tailwindcss/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e96</guid><category><![CDATA[CSS]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[My Experience]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 17 Mar 2021 19:47:43 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/cdb478e6ac1b7c0f03a1f431125aa79e/photo-1523437113738-bbd3cc89fb19.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/cdb478e6ac1b7c0f03a1f431125aa79e/photo-1523437113738-bbd3cc89fb19.jpg" alt="I Recreated a Bootstrap Website with Tailwind CSS, And Here Are The Differences"/><p>Every web developer starts with <a href="https://getbootstrap.com/">Bootstrap</a>. It's easy to use and saves so much time creating a website. Bootstrap is a necessity that every web developer relies on, whether beginner or advanced.</p><p>However, recently, I've been hearing a lot about<a href="https://tailwindcss.com/"> Tailwind CSS</a>. I kept seeing people on Twitter and articles talk about it, that I got curious and wanted to try it out.</p><p>So, I decided to recreate the website for <a href="https://github.com/sButtons/sbuttons">sButtons</a>, an open-source project I maintain. Originally, it was built with just HTML and Bootstrap. This is how it looked like:</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/old-sbuttons.png" class="kg-image" alt="I Recreated a Bootstrap Website with Tailwind CSS, And Here Are The Differences" loading="lazy"/></figure><p>The reason I chose to rebuild it was actually because it was getting hard to maintain all its components as it grew since it was just HTML. As it was easier to make these components reusable, I decided to recreate it with React, and also give it a different, new look as well.</p><p>As great as the first design was, I wanted to try something more flat, simple, and easier to navigate.</p><p>After building it with React and Tailwind CSS, this is the <a href="https://sbuttons.netlify.app/">new website</a>:</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/sButtons-Simple-buttons-you-can-use-easily-for-your-next-project-.png" class="kg-image" alt="I Recreated a Bootstrap Website with Tailwind CSS, And Here Are The Differences" loading="lazy"/></figure><p>A much simpler website that conveys the message behind "Simple buttons".</p><p>Although the design changed tremendously, this is not what I will be comparing here. What I will be comparing is my experience working with both Bootstrap and Tailwind CSS and which is better.</p><hr><h3 id="they-re-not-the-same">They're not The Same</h3><p>Although the purpose of Tailwind CSS and Bootstrap might be similar, however, they're different. Tailwind CSS is more focused on providing easy-to-use utility classes to save you time. As their documentation says: "No more adding silly class names like <code class="language-text">sidebar-inner-wrapper</code> just to be able to style something." It also encourages creating reusable components with these utility classes. </p><p>Bootstrap also provides easy-to-use utility classes, however, from its early versions, Bootstrap is focused on helping you create websites quickly by providing you with designed common UI elements. Just by copy-pasting the code, you will get a navigation bar on your website.</p><hr><h3 id="adapting-to-change">Adapting To Change</h3><p>When I first started trying out Tailwind CSS, I struggled a little as I was used to just use whatever ready-made components Bootstrap provides me then make changes on them accordingly. With Tailwind CSS, I had to create those components myself, which at first I thought would cost me more time and effort.</p><p>However, as I kept learning it and getting the hang of it, it kept getting easier and easier. My thinking directly shifted to the "Tailwind CSS" mindset, and building components got easier. I no longer had to rely on copy-pasting code. The utility classes Tailwind CSS provides help you understand how you are creating and styling your components, and you can do that without having to actually write CSS.</p><p>I got so used to using the classes Tailwind CSS provides, that even when I'm working on other projects my first instinct is to use them. </p><hr><h3 id="responsive-design-and-dark-mode-made-easy">Responsive Design and Dark Mode Made Easy</h3><p>Among many of Tailwind CSS's available classes, you can easily make any rule or class adhere to responsive design by adding a prefix to it based on the screen size you're targeting.</p><p>For example, if I want to make an element's width <code class="language-text">50%</code> on all screens, but make it <code class="language-text">100%</code> on small screens, I can do it easily like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>md:w-6/12 w-full<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>I'm responsive!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span></code></pre></div><p>No need to struggle with media queries anymore! You can add prefixes like <code class="language-text">md:</code>, <code class="language-text">sm:</code> and others as well to almost all utility classes provided by Tailwind CSS.</p><p>In Bootstrap, this is provided to some utility classes, however, I don't think it's flexible enough and you'll end up having to write your own media queries.</p><p>Next comes dark mode. Dark Mode is now a necessary feature of any website. Making your website dark mode compatible can be a hassle. It depends on how you build components in your website as well.</p><p>Tailwind CSS provides easy to use solution to make your website dark-mode compatible. Simply when styling elements, you can just add the prefix <code class="language-text">dark:</code> to add styling that will be applied only when dark mode is turned on. </p><p>For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>bg-white dark:bg-gray-700<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre></div><p>The classes added to the div ensure that by default, the background color should be white. However, if dark mode is turned on on the website, it should change its color to a shade of Gray.</p><p>Bootstrap at the moment of writing this does not provide any utility classes to help make implementing dark mode in your website easier, so this is a big bonus for Tailwind CSS as it also saves you a lot of time.</p><hr><h3 id="modern-feel">Modern Feel</h3><p>I've been using Bootstrap for many years now, and recently I started noticing that something about the design of components in Bootstrap feels outdated. Whether it's the colors or other design look and feel, it doesn't feel like it's adapting to changes of design pattern with time.</p><p>I really loved the <a href="https://tailwindcss.com/docs/customizing-colors">colors</a> that Tailwind CSS provides and how easy it is to customize them to get a bunch of other colors as well. Tailwind CSS provides a set of colors that you can use by default, but you can also change those colors easily from the configuration.</p><p>For example, when making the website, I found that Rose was better than the default Red. I was able to replace the shades of Red with the shades of Rose easily while still using the utility classes Tailwind CSS provides by just one line in the configuration:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">//tailwind.config.js</span> <span class="token literal-property property">red</span><span class="token operator">:</span> colors<span class="token punctuation">.</span>rose<span class="token punctuation">,</span></code></pre></div><hr><h3 id="using-it-with-react">Using It With React</h3><p>There are a lot of ways you can use Bootstrap with React. However, they can be a bit of a hassle. Usually, the library would create different React components that simulate Bootstrap components, and you have to import them to use them in your components.</p><p>Using Tailwind CSS with React is easy. You just need to make some changes in the configurations, then you can use the classes easily in your components. </p><p>The main difference here mostly relies on the fact that, as mentioned before, Bootstrap provides a lot of UI components rather than just utility classes. So, it's understandable why using it in React would be done this way. However, it felt much better to use Tailwind CSS with React, especially since you're constantly creating reusable components.</p><hr><h3 id="conclusion">Conclusion</h3><p>Both Bootstrap and Tailwind CSS have their own use cases that make them a better fit for a project. If you're unsure on which to use, assess what your priority is for your project and which option suits it better. </p></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Simple Twitter Bot Tutorial With Node.js Part 2: Deploy to Server and Schedule Tweets]]></title><description><![CDATA[In part 1, we learned how to create a simple Twitter bot with Node.js. In this article, we will go over how to deploy the bot and schedule tweets]]></description><link>https://blog.shahednasser.com/simple-twitter-bot-tutorial-with-node-part-2/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e95</guid><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Fri, 12 Mar 2021 10:04:56 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/643cec3669b3547a3a934eb5cc8f63a4/photo-1595287137144-cf60a87f39d9.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/643cec3669b3547a3a934eb5cc8f63a4/photo-1595287137144-cf60a87f39d9.jpg" alt="Simple Twitter Bot Tutorial With Node.js Part 2: Deploy to Server and Schedule Tweets"/><p><em>You can check out part 1 <a href="https://blog.shahednasser.com/simple-twitter-bot-tutorial-with-node-js/">here</a>.</em></p><p>In the previous article, we learned how to create a simple Twitter bot with Node.js that fetches data from the <a href="https://history.muffinlabs.com/">Today In History</a> API and tweets it in our account. </p><p>In this article, we will go over how to deploy the bot to a server and run the bot at a specific time in a day.</p><p>I have also created a new account for the History Bot rather than use my personal twitter account. You can check it out in live action <a href="https://twitter.com/HistoryBot7">@HistoryBot7</a></p><p>For the full code of this tutorial, you can check out the <a href="https://github.com/shahednasser/history-bot">GitHub repository</a>. If you haven't checked out <a href="https://blog.shahednasser.com/simple-twitter-bot-tutorial-with-node-js/">part 1</a> then I suggest you go over it a little.</p><hr><h3 id="deploying-the-bot">Deploying The Bot</h3><p>I will be deploying the bot that we created last time to <a href="/simple-twitter-bot-tutorial-with-node-part-2/alwaysdata.com">alwaysdata</a>. It's free and provides a lot of options that we need like scheduled tasks. However, you're free to deploy the bot to whatever server you want.</p><p>After creating an account if you don't have one, go to Accounts in the sidebar in the "Customer Area" section. You'll find a list of accounts if you have any or you can create a new one. These accounts are basically apps in your own main account. If you don't have any, click on "Add account"</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/administration-alwaysdata--2-.png" class="kg-image" alt="Simple Twitter Bot Tutorial With Node.js Part 2: Deploy to Server and Schedule Tweets" loading="lazy"/></figure><p>You will then need to enter account name which we will call "history-bot". alwaysdata will also use this account name for the subdomain you will get for free. Then in the Product dropdown choose Free Public Cloud. Check the checkboxes at the bottom and once you're done click "Submit"</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/administration-alwaysdata--3-.png" class="kg-image" alt="Simple Twitter Bot Tutorial With Node.js Part 2: Deploy to Server and Schedule Tweets" loading="lazy"/></figure><p>Once you click submit a new account will be created where you can add the bot to. Make sure that the account you created is selected in the sidebar menu in the dropdown field. If not, change to the account you created.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/administration-alwaysdata--4-.png" class="kg-image" alt="Simple Twitter Bot Tutorial With Node.js Part 2: Deploy to Server and Schedule Tweets" loading="lazy"/></figure><p>Now go to Sites under Web in the sidebar, and you will find a newly created site. Click edit to configure the site.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/administration-alwaysdata--5-.png" class="kg-image" alt="Simple Twitter Bot Tutorial With Node.js Part 2: Deploy to Server and Schedule Tweets" loading="lazy"/></figure><p>You can change the Name of the site and add any domain names if you own any. Then, go to the Configuration section and change the Type to "Node.js". In the Command field, enter <code class="language-text">node ~/history-bot/index.js</code> but make sure to replace <code class="language-text">history-bot</code> with the name of the app you created. In the working directory enter <code class="language-text">/home/history-bot/history-bot</code> the reason behind this is that I'm going to clone the <code class="language-text">history-bot</code> repository into the <code class="language-text">history-bot</code> app, so feel free to rename them based on what you have. The first one is the name of the app you created and the second one is the name of the repository.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/administration-alwaysdata--6-.png" class="kg-image" alt="Simple Twitter Bot Tutorial With Node.js Part 2: Deploy to Server and Schedule Tweets" loading="lazy"/></figure><p>Once you are done click Submit. Then in the sites listing, click on Restart to restart our site with the new configuration.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/administration-alwaysdata--7-.png" class="kg-image" alt="Simple Twitter Bot Tutorial With Node.js Part 2: Deploy to Server and Schedule Tweets" loading="lazy"/></figure><p>After restarting the site, we need to deploy the bot we created to it. To do this, we will need access to it with SSH. In the sidebar, go to SSH under Remote Access. Then, click on Edit and in the edit screen check the "Enable Password login" checkbox. </p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/administration-alwaysdata--8-.png" class="kg-image" alt="Simple Twitter Bot Tutorial With Node.js Part 2: Deploy to Server and Schedule Tweets" loading="lazy"/></figure><p>If you don't enter a password in the Password field, you will use your alwaysdata account password for SSH. To use a different password, enter it in the Password field.</p><p>Once you're done click Submit.</p><p>There are two ways to access your site with SSH. One is through a web interface alwaysdata have that you can see in the main page on the "SSH" section</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/administration-alwaysdata--9-.png" class="kg-image" alt="Simple Twitter Bot Tutorial With Node.js Part 2: Deploy to Server and Schedule Tweets" loading="lazy"/></figure><p>When you click on it it will ask you for you SSH name and password and if you enter them correctly, you can use the web terminal.</p><p>Another way to do this is by accessing from your terminal using <code class="language-text">ssh</code> command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">ssh</span> user@host</code></pre></div><p>Where <code class="language-text">user</code> can be found under <code class="language-text">Name</code> in the table and <code class="language-text">host</code> can be found in the yellow alert above the table. You will then be prompted to enter your password and when you do, you will be logged in.</p><p>Once you're in, enter the following command to clone your repository:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">git</span> clone https://github.com/shahednasser/history-bot.git</code></pre></div><p>If you don't have a repository for your bot, you should create one.</p><p>Then, go to the directory of the cloned repository:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> history-bot</code></pre></div><p>and run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span></code></pre></div><p>Now, we will need to create a new <code class="language-text">.env</code> file with our keys, so copy <code class="language-text">.env.sample</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">cp</span> .env.sample .env</code></pre></div><p>and edit the new <code class="language-text">.env</code> file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">nano</span> .env</code></pre></div><p>You will need to enter the keys you have, so make sure they're already saved and ready for use.</p><p>Once you're done, save the file. </p><p>To make sure that the bot is running correctly, run the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">node</span> index.js</code></pre></div><p>And if everything is working correctly, a new tweet should be sent to the account the keys belong to:</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/tweet.png" class="kg-image" alt="Simple Twitter Bot Tutorial With Node.js Part 2: Deploy to Server and Schedule Tweets" loading="lazy"/></figure><p>If any error occurs, make sure that the keys entered are correct. For more help, you can check <a href="https://blog.shahednasser.com/simple-twitter-bot-tutorial-with-node-js/">part 1</a> to make sure everything is configured correctly.</p><hr><h2 id="scheduling-tweets">Scheduling Tweets</h2><p>So, this is great but a bot should run on its own, not be activated manually. So, we will need to schedule for the bot to run every day.</p><p>Go back to alwaysdata and click on Scheduled Tasks under "Advanced". Then click on "Add a scheduled task"</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/administration-alwaysdata--10-.png" class="kg-image" alt="Simple Twitter Bot Tutorial With Node.js Part 2: Deploy to Server and Schedule Tweets" loading="lazy"/></figure><p>In the first section, choose "Execute the command" as type of task, and in Value type <code class="language-text">node ~/history-bot/index.js</code></p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/administration-alwaysdata--11-.png" class="kg-image" alt="Simple Twitter Bot Tutorial With Node.js Part 2: Deploy to Server and Schedule Tweets" loading="lazy"/></figure><p>In the Environment section, choose the SSH user you are using, and enter the Working directory we entered before.</p><p>Then in the Frequency section, choose Everyday and enter the time you want it to run at. Keep in mind that this time is relative to the timezone of the app you created, which by default is in Paris. To figure out what time it is in the app's timezone, run the following in the SSH terminal:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">date</span> <span class="token string">"+%H:%M:%S %d/%m/%y"</span></code></pre></div><p>I suggest for testing it now, set the time a few minutes after when you are going through this tutorial so that you can check that it works</p><p>Once you're done click Submit, and go back to the Sites section under Web and restart your app.</p><p>It should be noted that due to the simplicity we used to create the bot, we're always sending the first event we are receiving from the API. So, if you ran the bot before creating this task and a tweet went out, the scheduled task will run but will receive an error from Twitter that the "Status is a duplicate". To avoid this, make sure to remove the tweet you put out when testing the bot earlier.</p><p>Now, you have to wait until it's the time you chose for the bot to run at. Once it's time, give it a few seconds and check your account. If you find a new tweet then the bot is working! </p><p>If not, you can check the logs by going to <code class="language-text">~/admin/logs/jobs/2021</code> in your app and check the logs there. Make sure that everything is configured correctly. </p><p>Now, everyday at the time you sent, a Today in History tweet will go out to the account you specified!</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/History-Bot-on-Twitter-Year-538-Vitiges-king-of-the-Ostrogoths-ends-his-siege-of-Rome-and-retreats-to-Ravenna-leaving-the-city-in-the-hands-of-the-victorious-Byzantine-general-Belisarius-Twitter.png" class="kg-image" alt="Simple Twitter Bot Tutorial With Node.js Part 2: Deploy to Server and Schedule Tweets" loading="lazy"/></figure><hr><h3 id="conclusion">Conclusion</h3><p>In the next tutorial, we'll go over how to retweet specific hashtags made by other users!</p><p><em>You can check out part 3 <a href="https://blog.shahednasser.com/simple-twitter-bot-tutorial-part-3-search-and-retweet/">here</a>.</em></p></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[How to Download Any Website]]></title><description><![CDATA[If you ever need to download a website online and its content, this article will let you know how to easily do it with HTTrack.]]></description><link>https://blog.shahednasser.com/how-to-download-a-website/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e94</guid><category><![CDATA[Tips]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 08 Mar 2021 19:04:41 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/a53635c5030d2517d6a302c5947bea87/photo-1499951360447-b19be8fe80f5.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/a53635c5030d2517d6a302c5947bea87/photo-1499951360447-b19be8fe80f5.jpg" alt="How to Download Any Website"/><p>If you ever need to download a website online and its content, this article will let you know how to easily do it. Keep in mind that downloading the website's pages and content means downloading static files like HTML, CSS, Javascript, images, and other assets. </p><hr><p>First, we need to download a software called <a href="https://www.httrack.com/">HTTrack</a>. This software will do all the work for you. Go to the <a href="https://www.httrack.com/page/2/en/index.html">Download</a> page and download the installer that works the best for your system. Usually, the website will highlight the installer that's recommended for your system.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Download-HTTrack-Website-Copier-3-49-2-HTTrack-Website-Copier-Free-Software-Offline-Browser-GNU-GPL-.png" class="kg-image" alt="How to Download Any Website" loading="lazy"/></figure><p>After downloading the software and setting it up, you need to run it. It will prompt you to either start a new project (which means start downloading a website for the first time) or resume an old project, which is helpful if an error occurred in a previous time you were trying to download a website or you stopped halfway through. Click Next.</p><p><strong>Note: </strong>Depending on your system the screenshots will look different, but the same result can be achieved.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/httrack-1.png" class="kg-image" alt="How to Download Any Website" loading="lazy"/></figure><p>Then you'll be prompted to enter Project Name. This is just helpful if you want to reference it later, so name it the website you are trying to download.</p><p>I'll be downloading <a href="https://tailwindcss.com/">TailwindCSS</a>'s website, so I'll name it that. You can also specify the base directory the website will be stored in after downloading. Once you're done, click Next.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/httrack-2.png" class="kg-image" alt="How to Download Any Website" loading="lazy"/></figure><p>In the screen after you need to add the website's URL. You can add multiple URLs.</p><p>There are 3 ways to add a URL, either by pasting it in the textbox, or by clicking "Add URL...". This one is helpful if the website you are downloading requires some type of authentication. You can then enter a username and password that should be used for the website. You can also use the "Capture Link" method if the authentication to the website is a bit more complex.</p><p>The last way you can add URLs is through a txt file. If you have a .txt file that contains a list of URLs, you can choose to open the URLs from the file.</p><p>In the case of our example, I don't need authentication to access TailwindCSS, so I'll just paste the link in the textbox.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/httrack-3.png" class="kg-image" alt="How to Download Any Website" loading="lazy"/></figure><p>You can also set choose options like Proxy, or files to scan like zip files, mp3, or other types, choose the language, add HTTP headers, and much more. To access these options, click on "Set options".</p><p>For example, I'll add scanning for zip files as well. To do this, click on "Set options..." then the "Scan Rules" tab:</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/httrack-4.png" class="kg-image" alt="How to Download Any Website" loading="lazy"/></figure><p>Once you're done, click Next.</p><p>In the last step you can choose to save settings for later or what to do after the download is finished. If you don't need to make any changes just click Finish to start the download.</p><p>Now you will see the website download in progress. You can see details like the number of links scanned, files written, errors, and more.</p><p>Depending on the size of the website, this might take some time, so you have to wait for it to finish.</p><p>Once it's done, go to the path that was chosen in the beginning. You'll see a folder with the project name that we chose. You will see a bunch of folders with different URLs. Go to the URL you chose to download, in our case, it will be tailwindcss.com.</p><p>You will find <code class="language-text">index.html</code> file inside the directory. Open it in your favorite browser and you will find the full website you downloaded!</p><p>You can now go through the directories to check the assets and different pages in the website as well. </p></hr>]]></content:encoded></item><item><title><![CDATA[use-dark-mode-hook: A Simple Library To Add Dark Mode to Your React Project]]></title><description><![CDATA[use-dark-mode-hook is a simple library that allows you to easily add dark mode to your React projects.]]></description><link>https://blog.shahednasser.com/use-dark-mode-hook-a-simple-library/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e93</guid><category><![CDATA[Open Source]]></category><category><![CDATA[Projects]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Fri, 05 Mar 2021 20:08:19 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/a31f23226ff9e49e40d6b5dd3887a562/photo-1607027340685-3e1ae9a54a93.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/a31f23226ff9e49e40d6b5dd3887a562/photo-1607027340685-3e1ae9a54a93.jpg" alt="use-dark-mode-hook: A Simple Library To Add Dark Mode to Your React Project"/><p>I have created a new library called <a href="https://www.npmjs.com/package/use-dark-mode-hook">use-dark-mode-hook</a>. It's a simple library that allows you to easily add dark mode to your React projects.</p><p>This library provides a custom hook <code class="language-text">useDarkMode</code> and a button toggler component <code class="language-text">DarkModeToggler</code>. You can use them together or separately. However, this library does <strong>not</strong> provide any styling regarding dark and light modes. You have to do that yourself.</p><hr><h3 id="purpose">Purpose</h3><p>As I was trying to add Dark mode in my react project, I noticed that there are packages out there that do provide this, however, either they don't work with the latest React version or they only provide the functionality or UI. Thus, I decided to create a simple hook that adds the dark mode functionality to the website, and a component that provides a toggling button.</p><hr><h3 id="installation">Installation</h3><p>To install the package:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> i use-dark-mode-hook</code></pre></div><hr><h2 id="usage">Usage</h2><h3 id="usedarkmode-darkmodetoggler">useDarkMode + DarkModeToggler</h3><p>To use both the functionality and UI (more details about the options of each in below sections):</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> useDarkMode<span class="token punctuation">,</span> <span class="token punctuation">{</span> DarkModeToggler <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'use-dark-mode-hook'</span> <span class="token keyword">function</span> <span class="token function">MyComponent</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>isDarkMode<span class="token punctuation">,</span> toggleDarkMode<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useDarkMode</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>DarkModeToggler isDarkMode<span class="token operator">=</span><span class="token punctuation">{</span>isDarkMode<span class="token punctuation">}</span> toggleDarkMode<span class="token operator">=</span><span class="token punctuation">{</span>toggleDarkMode<span class="token punctuation">}</span> buttonClassName<span class="token operator">=</span><span class="token string">"some-classes"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>That's it! <code class="language-text">useDarkMode</code> will manage the state and logic while <code class="language-text">DarkModeToggler</code> provides a toggle button for the user to toggle dark mode.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/demo.gif" class="kg-image" alt="use-dark-mode-hook: A Simple Library To Add Dark Mode to Your React Project" loading="lazy"/></figure><p>By default, <code class="language-text">useDarkMode</code> will apply either <code class="language-text">dark</code> or <code class="language-text">light</code> class to the <code class="language-text">body</code> of the document based on the choice of the user. You can change the names of the classes by passing <code class="language-text">darkModeClass</code> and <code class="language-text">lightModeClass</code> to <code class="language-text">useDarkMode</code>, and change the element the class will be applied to by passing its selector in <code class="language-text">element</code> to <code class="language-text">useDarkMode</code>. You can check out the all the options <a href="https://github.com/shahednasser/use-dark-mode-hook#options">here</a>.</p><h3 id="usedarkmode-hook">useDarkMode hook</h3><p>You can use the hook separately with your own toggler:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> useDarkMode <span class="token keyword">from</span> <span class="token string">'use-dark-mode-hook'</span> <span class="token keyword">function</span> <span class="token function">myComponent</span> <span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>isDarkMode<span class="token punctuation">,</span> toggleDarkMode<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useDarkMode</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//do something with it</span> <span class="token punctuation">}</span></code></pre></div><p>You'll have to use <code class="language-text">isDarkMode</code> as the current state of dark mode, and <code class="language-text">toggleDarkMode</code> to toggle dark mode. <code class="language-text">toggleDarkMode</code> takes a boolean specifying whether dark mode is enabled or disabled.</p><h3 id="darkmodetoggler">DarkModeToggler</h3><p>You can use the toggler separately with your own logic:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> DarkModeToggler <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'use-dark-mode-hook'</span> <span class="token keyword">function</span> <span class="token function">MyComponent</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//some code</span> <span class="token keyword">function</span> <span class="token function">toggleDarkMode</span> <span class="token punctuation">(</span><span class="token parameter">checked</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//logic to toggle dark mode</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>DarkModeToggler isDarkMode<span class="token operator">=</span><span class="token punctuation">{</span>value<span class="token punctuation">}</span> toggleDarkMode<span class="token operator">=</span><span class="token punctuation">{</span>toggleDarkMode<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div><p>For <code class="language-text">isDarkMode</code> you have to pass the current value of whether dark mode is enabled or not, and for <code class="language-text">toggleDarkMode</code> it should be a function that takes a boolean for whether dark mode is enabled or not.</p><hr><h3 id="contribution">Contribution</h3><p>If you find any issues or bugs, or would like to contribute to this library, please check out the <a href="https://github.com/shahednasser/use-dark-mode-hook">GitHub repository</a>.</p></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Tips For Beginners to Open Source]]></title><description><![CDATA[As a maintainer I noticed the same mistakes beginners make or some things that confuse them. In this article, I will hopefully resolve all your confusion]]></description><link>https://blog.shahednasser.com/tips-for-beginners-to-open-source/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e92</guid><category><![CDATA[Open Source]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sun, 28 Feb 2021 11:41:15 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/e3c1b29a1332fdc7f035fd9b7774cf21/photo-1555949963-ff9fe0c870eb.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/e3c1b29a1332fdc7f035fd9b7774cf21/photo-1555949963-ff9fe0c870eb.jpg" alt="Tips For Beginners to Open Source"/><p>I've been a maintainer to a couple of repositories now that specifically aim to help beginners to learn how to contribute to open source and give them a chance. It's been a great journey you can read about it in my other article <a href="https://blog.shahednasser.com/how-i-learned-about-contributing-to-open-source-projects-by-creating-one/">How I Learned About Contributing to Open Source Projects By Creating One</a>.</p><p>Through my time as a maintainer, I noticed the same mistakes beginners make or the same issues they get confused about. That's why I decided to put it all in one article in the hopes that it helps any beginner out there looking forward to contributing to open source projects.</p><hr><h3 id="read-the-contribution-guidelines">Read the Contribution Guidelines</h3><p>Almost in every open-source repository, you'll find a file called <code class="language-text">CONTRIBUTING.MD</code>. This file will hold all the rules of contributing to this repository, a guide to how to make changes, and how you can contribute. It is very important that you read it as it can save you a lot of time figuring out what you need to do and can make sure that your pull requests (or PRs) will be following all the guidelines of the project, which will save time for the maintainers to review it and provide the changes to be made.</p><hr><h3 id="create-a-new-branch">Create a New Branch</h3><p>The first step you need to do when contributing to a project is forking it so that you can make the changes and commit them. But a step a lot of beginners miss is that you need to create a new branch. Do not fork then make changes to the master branch. This is extremely helpful for maintainers as well and for the project as a whole.</p><hr><h3 id="get-assigned-to-issues-before-working-on-them">Get Assigned to Issues Before Working On Them</h3><p>This might be different in some open-source projects, but I think it applies to most. Usually, when contributing to a project, you'll go to the issues section of the repository to see what help is needed. When you find an issue that you think you can work on, first make sure that it is unassigned, then comment on it asking to be assigned. A lot of contributors look over the fact that an issue is assigned to someone else, or forget to comment on an issue, which causes confusion when looking over PRs that resolve the same issue. To avoid that, comment on the issue first, get assigned then submit your PR.</p><hr><h3 id="before-submitting-a-pr-create-an-issue">Before Submitting A PR, Create An Issue</h3><p>This one applies to when you find a bug or have an idea for an enhancement, and it is not in the issues section of the repository. A lot of contributors proceed to just fixing it and sending a PR. Sometimes when it's something small like a typo fix it's not a big deal, however, when it's a big change, especially if it's based on what you think is better, make sure to send an issue with the suggestion or bug report first. If the maintainers find that you are right, they'll assign you the issue. If, however, they find it doesn't work for this project for one reason or another, then they'll close it and it will save both your time and theirs.</p><hr><h3 id="you-don-t-need-to-create-a-new-pr-for-every-change">You Don't Need to Create A New PR For Every Change</h3><p>I've seen a lot of confusion about this. A contributor would send in a PR, I'd request changes, then the contributor proceeds to closing the PR and submitting the new one with the changes requested. You don't need to do that. </p><p>When you want to make changes to a PR, just make the changes then commit them to the repository you sent the PR from. Let's say you forked the repository and created a new branch <code class="language-text">patch-1</code>, then make changes in that branch and just commit and push your changes. The changes will automatically show in the PR.</p><hr><h3 id="don-t-commit-unnecessary-files">Don't Commit Unnecessary Files</h3><p>I've received PRs that include commits to files that are not necessary for the project, like your IDE's configuration files. Before committing your changes, look at what has changed and only commit what applies to the issue you are working on.</p><hr><h3 id="don-t-be-discouraged">Don't Be Discouraged</h3><p>My favorite contributor was actually someone who messed up a lot. The reason behind that is that they kept telling me they were a beginner and they made a lot of mistakes, so I had to keep asking them for changes. I honestly thought at some point that they'll close the PR and just quit. However, they kept trying and with time not only did they provide the needed result, but also contributed to other issues as well. It's ok to make mistakes in the beginning, it's how you learn to do better next time.</p><hr><h3 id="conclusion">Conclusion</h3><p>If you've never contributed to open-source projects or you are hesitant about it, you should start now. It's very important and will help you a lot by giving back to the community. Look at the tips above to help you and start with easy projects. Even small contributions that you can make will help.</p></hr></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Simple Twitter Bot Tutorial with Node.js]]></title><description><![CDATA[In this tutorial, we'll go over creating a simple Twitter bot that uses the Today in History API and tweet what happened today in history.]]></description><link>https://blog.shahednasser.com/simple-twitter-bot-tutorial-with-node-js/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e91</guid><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 27 Feb 2021 22:07:37 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/9261b39d387ffe201fb8270d12c95685/photo-1551817958-d9d86fb29431.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/9261b39d387ffe201fb8270d12c95685/photo-1551817958-d9d86fb29431.jpg" alt="Simple Twitter Bot Tutorial with Node.js"/><p><em>You can check out part 2 <a href="https://blog.shahednasser.com/simple-twitter-bot-tutorial-with-node-part-2/">here</a> and part 3 <a href="https://blog.shahednasser.com/simple-twitter-bot-tutorial-part-3-search-and-retweet/">here</a>.</em></p><p>You've probably seen so many Twitter bots on Twitter these days and thought "Hmm, how can I also create one?" </p><p>In this tutorial, we'll go over creating a simple Twitter bot that uses the <a href="https://history.muffinlabs.com/">Today in History</a> API and tweet what happened today in history. We'll call it History Bot. You can find the repository with the full code <a href="https://github.com/shahednasser/history-bot">here</a>.</p><hr><h3 id="creating-the-twitter-app">Creating The Twitter App</h3><p>Before getting started in the technical part, we first need to create a Twitter App. First, log in to <a href="https://developer.twitter.com/">Twitter Developer's portal</a> with the Twitter account you want the bot to tweet from. </p><p>Once you do that, go <a href="https://developer.twitter.com/en/portal/apps/new">here</a> to create a new app. You can also find this under Projects & Apps > Overview > Create App.</p><p>You will be asked to enter information like the name of the app, description of the app, and what you will be using the app for. Once you're done, you'll be shown a set of keys. You don't need to save those keys yet, as we will regenerate them later. Just scroll down and click on App Settings.</p><p>When you go to your app's dashboard, click on the Settings tab, then scroll down to App permissions. You will see that it says Read. We need to change that to Read and Write if we're going to be tweeting, so click on the edit button and choose Read + Write from the list, then click Save.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Twitter-Developers--1-.png" class="kg-image" alt="Simple Twitter Bot Tutorial with Node.js" loading="lazy"/></figure><p>Now, go back to the Keys and tokens page, scroll down to Access token & secret and click Regenerate. The reason we need to regenerate them is that the initial tokens are only for the Read permission and cannot be used to add a tweet, i.e. Write. Once you click Regenerate and get the new keys, make sure to save them as you can't see them later unless you regenerate again.</p><p>You will also need to Regenerate the API key & secret if you don't have them. If you do, make sure to save them for later use as well.</p><hr><h3 id="creating-the-bot">Creating The Bot</h3><p>Now we'll get to the technical part. We first need to initialize our project:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">mkdir</span> history-bot <span class="token builtin class-name">cd</span> history-bot <span class="token function">npm</span> init</code></pre></div><p>When you run <code class="language-text">npm init</code>, you will need to enter a few information like package name or description. You can also skip that and go with the default settings by running <code class="language-text">npm init -y</code></p><p>When you are done with the above commands you will have the skeleton of the project. </p><p>Next, we will install the <a href="https://github.com/FeedHive/twitter-api-client">twitter-api-client</a> package for easy interaction with Twitter's API:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> i twitter-api-client</code></pre></div><p>To use our tokens and API keys securely, we'll use the dotenv package: </p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> i dotenv</code></pre></div><p>Next, create <code class="language-text">.env</code> file that should hold the following keys:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">TWITTER_API_KEY= TWITTER_API_SECRET= TWITTER_ACCESS_TOKEN= TWITTER_ACCESS_TOKEN_SECRET=</code></pre></div><p><strong>Note</strong>: if you are using the repository's code, there's a <code class="language-text">.env.sample</code> file that you can rename to <code class="language-text">.env</code> and add your keys in it.</p><p>Add the keys that you saved before in <code class="language-text">.env</code> and save the file.</p><p>Now, create <code class="language-text">index.js</code> which will hold our code. We will start the script by requiring the packages we will use:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'dotenv'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">{</span>TwitterClient<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'twitter-api-client'</span><span class="token punctuation">)</span></code></pre></div><p>The first line ensures that we can use the variables we added in our <code class="language-text">.env</code> file.</p><p>Then, we will create a Twitter client using our credentials in <code class="language-text">.env</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> twitterClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TwitterClient</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">apiKey</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_API_KEY</span><span class="token punctuation">,</span> <span class="token literal-property property">apiSecret</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_API_SECRET</span><span class="token punctuation">,</span> <span class="token literal-property property">accessToken</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_ACCESS_TOKEN</span><span class="token punctuation">,</span> <span class="token literal-property property">accessTokenSecret</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_ACCESS_TOKEN_SECRET</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>So let's go back to what we said the bot will do. The bot will fetch from the Today in History API what happened on this day in history, then it will tweet it to our account. To send the request to the API, we will need to install axios:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> i axios</code></pre></div><p>Let's take a little look at the API. A GET request to the endpoint <a href="https://history.muffinlabs.com/date">https://history.muffinlabs.com/date</a> will give us an object similar to this:</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/today-in-history.png" class="kg-image" alt="Simple Twitter Bot Tutorial with Node.js" loading="lazy"/></figure><p>So, the response is an object that has the properties <code class="language-text">date</code>, <code class="language-text">url</code>, and <code class="language-text">data</code>. Inside <code class="language-text">data</code> there's the <code class="language-text">Events</code> property that holds an array of events that happened on this day in history. In this tutorial, we'll just tweet the first item in the array.</p><p>We will add the following code to send the request to the API and retrieve the events: </p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript">axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'http://history.muffinlabs.com/date'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">response</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> data <span class="token operator">=</span> response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>data <span class="token operator">?</span> response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>data <span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token keyword">let</span> tweet <span class="token keyword">if</span> <span class="token punctuation">(</span>data<span class="token punctuation">.</span>Events <span class="token operator">&&</span> data<span class="token punctuation">.</span>Events<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//tweet the first event in the array</span> tweet <span class="token operator">=</span> <span class="token string">'Year '</span> <span class="token operator">+</span> data<span class="token punctuation">.</span>Events<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>year <span class="token operator">+</span> <span class="token string">' - '</span> <span class="token operator">+</span> data<span class="token punctuation">.</span>Events<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>text <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> tweet <span class="token operator">=</span> <span class="token string">'Nothing happened today :)'</span> <span class="token punctuation">}</span> <span class="token comment">//TODO send the tweet</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span> <span class="token punctuation">(</span><span class="token parameter">err</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>Here's what we are doing here in details:</p><p>We are sending a GET request to the endpoint, then we are getting the data through <code class="language-text">response.data</code>. Since the response object has the property <code class="language-text">data</code> which holds <code class="language-text">Events</code>, we are assigning it to a new variable <code class="language-text">data</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> data <span class="token operator">=</span> response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>data <span class="token operator">?</span> response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>data <span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code></pre></div><p>Next, we are setting the tweet that we will be sending. If in the data object received there's an <code class="language-text">Event</code> property and that holds at least one item, we are setting the tweet to the year plus the text:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">if</span> <span class="token punctuation">(</span>data<span class="token punctuation">.</span>Events <span class="token operator">&&</span> data<span class="token punctuation">.</span>Events<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//tweet the first event in the array</span> tweet <span class="token operator">=</span> <span class="token string">'Year '</span> <span class="token operator">+</span> data<span class="token punctuation">.</span>Events<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>year <span class="token operator">+</span> <span class="token string">' - '</span> <span class="token operator">+</span> data<span class="token punctuation">.</span>Events<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>text <span class="token punctuation">}</span></code></pre></div><p>If the Events property is not received or there are no events on this day, we will set the tweet into a default text:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">else</span> <span class="token punctuation">{</span> tweet <span class="token operator">=</span> <span class="token string">'Nothing happened today :)'</span> <span class="token punctuation">}</span></code></pre></div><p>We also added a catch to the GET request in case an error occurs:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">.</span><span class="token function">catch</span> <span class="token punctuation">(</span><span class="token parameter">err</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>What is left is to use the Twitter client we created earlier to send the tweet to our account. We will use the <code class="language-text">twitterClient.tweets.statusesUpdate</code> method which can take many optional parameters (you can check out all the details <a href="https://github.com/FeedHive/twitter-api-client/blob/master/REFERENCES.md#twitterclienttweetsstatusesupdateparameters">here</a>), but requires one parameter <code class="language-text">status</code> which is the text of the tweet.</p><p>This will be the code to send the tweet:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript">twitterClient<span class="token punctuation">.</span>tweets<span class="token punctuation">.</span><span class="token function">statusesUpdate</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">status</span><span class="token operator">:</span> tweet <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span> <span class="token punctuation">(</span><span class="token parameter">response</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Tweeted!"</span><span class="token punctuation">,</span> response<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>If the tweet goes through, we will log to the console "Tweeted" with the response object. If an error occurs, we will log to the console the error.</p><p>Now, our script should look like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'dotenv'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">{</span>TwitterClient<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'twitter-api-client'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> axios <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'axios'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> twitterClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TwitterClient</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">apiKey</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_API_KEY</span><span class="token punctuation">,</span> <span class="token literal-property property">apiSecret</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_API_SECRET</span><span class="token punctuation">,</span> <span class="token literal-property property">accessToken</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_ACCESS_TOKEN</span><span class="token punctuation">,</span> <span class="token literal-property property">accessTokenSecret</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_ACCESS_TOKEN_SECRET</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'http://history.muffinlabs.com/date'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">response</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> data <span class="token operator">=</span> response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>data <span class="token operator">?</span> response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>data <span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token keyword">let</span> tweet <span class="token keyword">if</span> <span class="token punctuation">(</span>data<span class="token punctuation">.</span>Events <span class="token operator">&&</span> data<span class="token punctuation">.</span>Events<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//tweet the first event in the array</span> tweet <span class="token operator">=</span> <span class="token string">'Year '</span> <span class="token operator">+</span> data<span class="token punctuation">.</span>Events<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>year <span class="token operator">+</span> <span class="token string">' - '</span> <span class="token operator">+</span> data<span class="token punctuation">.</span>Events<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>text <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> tweet <span class="token operator">=</span> <span class="token string">'Nothing happened today :)'</span> <span class="token punctuation">}</span> twitterClient<span class="token punctuation">.</span>tweets<span class="token punctuation">.</span><span class="token function">statusesUpdate</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">status</span><span class="token operator">:</span> tweet <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span> <span class="token punctuation">(</span><span class="token parameter">response</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Tweeted!"</span><span class="token punctuation">,</span> response<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span> <span class="token punctuation">(</span><span class="token parameter">err</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div><p>We are ready to run the script to send the tweet now.</p><p>Go to <code class="language-text">package.json</code> and add inside <code class="language-text">scripts</code> the start script:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"start"</span><span class="token operator">:</span> <span class="token string">"node index.js"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div><p>Then, in your terminal or command line, run:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> start</code></pre></div><p>If all steps are done correctly, you will see in your console "Tweeted" with the response object. You can also go to the account you created the app from on Twitter and you will see your tweet!</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/IMG_3612.png" class="kg-image" alt="Simple Twitter Bot Tutorial with Node.js" loading="lazy"/></figure><p>If you encounter an error related to authentication or authorization, make sure that all your keys and tokens are correct and make sure that you have enabled the Read + Write permissions.</p><hr><h3 id="conclusion">Conclusion</h3><p>Congrats, you've created your first Twitter bot! I suggest you go through <a href="https://developer.twitter.com/en/docs/twitter-api">Twitter's documentation</a> and the <a href="https://github.com/FeedHive/twitter-api-client">twitter-api-client</a> package as well to see what more you can do with your Twitter bot.</p><p><em>You can check out part 2 <a href="https://blog.shahednasser.com/simple-twitter-bot-tutorial-with-node-part-2/">here</a> and part 3 <a href="https://blog.shahednasser.com/simple-twitter-bot-tutorial-part-3-search-and-retweet/">here</a>.</em></p></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[I Created More Logos With CSS]]></title><description><![CDATA[In my last post, I created famous logos with CSS. I received from the readers a few logos to challenge myself with as well that are on the next level.]]></description><link>https://blog.shahednasser.com/i-created-more-logos-with-css/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e90</guid><category><![CDATA[CSS]]></category><category><![CDATA[Beginners]]></category><category><![CDATA[Design]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 24 Feb 2021 19:28:57 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/8c68b9a02e4f049347fa44735013a1c9/photo-1561070791-2526d30994b5.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/8c68b9a02e4f049347fa44735013a1c9/photo-1561070791-2526d30994b5.jpg" alt="I Created More Logos With CSS"/><p>In my last post, I <a href="https://blog.shahednasser.com/i-created-famous-logos-with-css/">created famous logos with CSS</a>. It was a nice challenge as I haven't practiced CSS this way in a while.</p><p>After posting it and asking for the reader's suggestions for my next challenge, I received a few that definitely were on the next level of difficulty. Although the number of logos is less this time, the challenge was definitely bigger for me. I also was able to use a lot of the concepts I practiced last time in this one, which helped immensely.</p><p>Just like last time, these logos are sorted from least difficult to most difficult.</p><hr><h3 id="vs-code">VS Code</h3><p>This was suggested by <a href="https://dev.to/meherabsamir">MeherabSamir</a>. I actually was thinking of doing this one before it was suggested, but since it was suggested it encouraged me more to do it.</p><p>When I did this one, I expected it to be much harder than it actually was:</p><!--kg-card-begin: html--><p class="codepen" data-height="419" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="poNWJXj" style="height: 419px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="VS Code"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/poNWJXj"> VS Code</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>This was actually the first one I worked on in this list, and through it, I got to practice and understand perspective more, which I haven't used in a long time.</p><hr><h3 id="red-hat">Red Hat</h3><p>This was suggested by <a href="https://dev.to/luxzg">luxzg</a>, and this was definitely the hardest. So why am I putting it this early? Well, because I couldn't do it the way I was supposed to. <a href="https://dev.to/luxzg">luxzg</a> challenged me to do the logo not just the hat, with the face as well. After trying for hours to achieve that, I was not satisfied with the result and I opted to do just the hat, which wasn't easy either.</p><!--kg-card-begin: html--><p class="codepen" data-height="366" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="ExNbXKZ" style="height: 366px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Red Hat"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/ExNbXKZ"> Red Hat</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>Although it's not perfect and I wasn't exactly able to fulfil the challenge fully, I still wanted to include it in the hopes I can do a better job another time.</p><hr><h3 id="github">GitHub</h3><p>This was also suggested by <a href="https://dev.to/meherabsamir">MeherabSamir</a>. This one I was so confused on how I can actually do it, but I think it turned out well. The only thing bothering me about it is the ears as for some reason they look off, but other than that I'm proud of the result.</p><!--kg-card-begin: html--><p class="codepen" data-height="388" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="mdOBjdG" style="height: 388px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="GitHub"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/mdOBjdG"> GitHub</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>I experienced a problem with this, however, that is also visible in the next logo, which is when I added <code class="language-text">overflow: hidden</code> to the container, you can see a black outline around the circle (it's visible in the white areas). I tried looking up a solution for it, however, I couldn't find anything. </p><p>If anyone knows a fix for this, please let me know in the comments!</p><p><strong>UPDATE</strong>: <a href="https://dev.to/afif">Temani Afif</a> helped me resolve this so thank you!</p><hr><h3 id="hitchhiker-s-guide-to-the-galaxy">Hitchhiker's Guide to The Galaxy</h3><p>This was suggested by <a href="https://dev.to/tqbit">tq-bit</a>. <a href="https://dev.to/tqbit">tq-bit</a> said that this one is basically not "humanly possible." As I Googled the logo, there were different versions of it, so I picked the first one. I'm not sure if this is the one they meant, but if it is then I would like to tell them that what seems impossible is possible! (And if that's not the one, please play along as it makes me happy)</p><!--kg-card-begin: html--><p class="codepen" data-height="367" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="dyOZvzB" style="height: 367px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Hitchhiker's Guide to the Galaxy"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/dyOZvzB"> Hitchhiker's Guide to the Galaxy</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>I experienced the same problem with this as the one previously which is the black outline. The hardest part about this one was the hand shape and making it as similar as possible. Took me a few hours to do it, but it was worth it as the result was satisfying (to me at least).</p><hr><h3 id="conclusion">Conclusion</h3><p>Although this list is shorter than the one before, but I have learned so much through this one and was able to challenge myself on a higher level. </p><p>I'm hoping to do next something more 3D or that has an animation in it. Let me know if you have any suggestions!</p></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Grammarly With Ghost: An Extension to Make Your Blogging Easier]]></title><description><![CDATA[If you use Ghost CMS and you need Grammarly, you probably noticed that it does not work with Ghost's editor Koenig. So, I created an extension to fix it.]]></description><link>https://blog.shahednasser.com/grammarly-with-ghost-an-extension-to-make-your-blogging-easier/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e8f</guid><category><![CDATA[Projects]]></category><category><![CDATA[My Experience]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 22 Feb 2021 11:35:26 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/1abb7c02bb4b881792a788ec21b75129/photo-1500989145603-8e7ef71d639e.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/1abb7c02bb4b881792a788ec21b75129/photo-1500989145603-8e7ef71d639e.jpg" alt="Grammarly With Ghost: An Extension to Make Your Blogging Easier"/><p>If you use <a href="https://ghost.org/">Ghost</a> for your blogging needs and you need Grammarly as well to make your life easier, you probably noticed that Grammarly does not work with Ghost's editor Koenig.</p><p>You can read more about it at these links:</p><ul><li><a href="https://github.com/TryGhost/Ghost/issues/11252">Grammarly support for the Koenig editor Issue</a></li><li><a href="https://forum.ghost.org/t/grammarly-support/2220">Ghost Forum: Grammarly Support</a></li></ul><hr><h2 id="the-solution">The Solution</h2><p><br>While looking through the above links, I saw different people saying that you can get Grammarly to work with Ghost's editor by merely removing the attribute <code class="language-text">data-gramm="false"</code>. I tried doing that with my own blog and it worked!</br></p><p>It should be noted that the reason behind Grammarly not working with Ghost's editor is due to it not supporting it. So, I am not sure if this solution will cause any problems on your side. For me, it works perfectly well. There's an issue detailed <a href="https://gitmemory.com/issue/TryGhost/Ghost/11252/671525102">here </a>about clicking on "Edit in Grammarly," however, I couldn't reproduce it.</p><hr><h2 id="the-extension">The Extension</h2><p><br><strong>Note: This extension assumes you already have the Grammarly extension installed in your browser</strong></br></p><p>So, the extension basically detects the element with the attribute <code class="language-text">data-gramm="false"</code> and removes that, while also doing some check on the height and width of the element (you can read more about it <a href="https://support.grammarly.com/hc/en-us/articles/115000090392-I-do-not-see-the-G-icon-on-a-certain-web-page-or-in-a-certain-text-field-but-see-it-on-other-web-pages-">here</a>)</p><h3 id="before-installing-the-extension">Before Installing The Extension</h3><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/before.png" class="kg-image" alt="Grammarly With Ghost: An Extension to Make Your Blogging Easier" loading="lazy"/></figure><p>Before installing the extension, Grammarly does not work with Ghost's editor and you will not be notified of any errors in your writing.</p><h3 id="after-installing-the-extension">After Installing the Extension</h3><p>Once you install the extension, you need to open your Ghost blog, then click on the icon of the extension. After that, you can enable the extension to work on this host or domain.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/enable--1-.png" class="kg-image" alt="Grammarly With Ghost: An Extension to Make Your Blogging Easier" loading="lazy"/></figure><p>Once you enable it, it will do the work specified above whenever necessary. If you do not enable it for the domain you need it to work on, it will not do anything.</p><h3 id="after-enabling">After Enabling</h3><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/after.png" class="kg-image" alt="Grammarly With Ghost: An Extension to Make Your Blogging Easier" loading="lazy"/></figure><hr><h2 id="downloading-the-extension">Downloading the Extension</h2><p>You can download the extension <a href="https://chrome.google.com/webstore/detail/grammarly-with-ghost/iakfoofepmfjafjepidembmheemidbdb">here</a>.</p><hr><h2 id="contribution">Contribution</h2><p>If you find any issues and bugs in the extension or have any ideas missing in it, you are welcome to open an issue with it at the <a href="https://github.com/shahednasser/grammarly-ghost">GitHub repository</a>!</p><hr><h2 id="attributions">Attributions</h2><ul><li>Toggle button is from <a href="https://github.com/sButtons/sbuttons">sButtons</a></li><li>Extension icon is from <a href="https://iconscout.com/contributors/dinosoftlabs">Dinosoft Lab on Iconscout</a></li></ul></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[How A Technical Interview Made Me Not Want A Job]]></title><description><![CDATA[It's time for companies to realize that when you're looking for an employee, there are far more important qualities you need to look for in them.]]></description><link>https://blog.shahednasser.com/how-a-technical-interview-made-me/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e8e</guid><category><![CDATA[My Experience]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 20 Feb 2021 09:53:53 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/668f824de0560f8ee45c65a36733bdd7/photo-1471238119891-2e56eca253b4.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/668f824de0560f8ee45c65a36733bdd7/photo-1471238119891-2e56eca253b4.jpg" alt="How A Technical Interview Made Me Not Want A Job"/><p><em><a href="https://jooble.org/jobs-web-developer">Find Web Development Jobs at Jooble!</a></em></p><p>Summer of last year, I stumbled on a job ad on LinkedIn for a position for a Freelance React developer at a company overseas. I got excited and applied, having high expectations of the company. </p><p>A few days after, I was contacted by the company's HR on LinkedIn. She asked me a few questions at first about myself and my skills, then told me that I need to finish a technical assessment test. The assessment test would be done through an online portal and would be an hour long.</p><p>I agreed and asked what would the assessment test cover, and the HR answered "Concepts basically. The test will just check your knowledge about React"</p><p>I was more than fine with that, as I have a lot of experience in React and would consider myself pretty skilled at it. However, I still went through the documentation for React in general, to make sure that I am ready and I didn't miss or forget anything.</p><p>After prepping for the test, I went into the test with full confidence, to be completely surprised. The test had two questions related to basic mathematics, and one of them was writing a function that computes the GCD/LCM. </p><p>My first reaction, to be completely honest, was "?????". How is that related to my React knowledge? Why would you test me with such basic and irrelevant questions? I'm aware that the test could be to check my code, how I think, or how my approach would be, but couldn't it be a little more related to the job I'm actually applying for? Isn't the company at least aware that such a basic question anyone can easily google and find the code for online?</p><p>After thinking about it, I closed the test and contacted the HR telling her I'm no longer interested in the job.</p><hr><h2 id="it-s-time-for-a-change">It's Time For A Change</h2><p><br>This isn't the first or only company that does this. So many companies rely on these sorts of tests to hire their talents. But isn't it time to move away from these tests? Do we still need to test people on such old concepts and methods? </br></p><p>Anyone who has worked a day in their life in this industry knows that it's not about the code or how high your technical skills are. You need people who are willing and are ready to learn and grow. You need people who think outside the box, who will provide solutions to real-life problems, who will take on challenges and provide the best results.</p><p>Another thing we should consider is that the beginners of today are different than when we were beginners years ago. Beginners today don't need to learn, in my own opinion, older concepts that are no longer relevant now. Beginners today are starting with newer concepts, frameworks, ways of thinking, and even ways of learning, and companies should start looking into that.</p><p>In addition to all of that, it's time we acknowledge that it's more than ok to not remember the simple details of some programming language skills that we can simply Google. In fact, it's time we acknowledge that "Googling" should be a skill that you need to master. It will save you so much time and will <em>not</em> make you less of a good developer.</p><p> I hope companies stop with these useless technical interviews. It's time for companies to realize that when you're looking for an employee or a freelancer or a developer for any sort of role, there are far more important qualities you need to look for in the person you're hiring. Assess their creativity and their approach to unique or real-life problems. Take into account their personality and work ethics. Figure out if you're investing in talents, or you're just hiring a coding machine. </p></hr>]]></content:encoded></item><item><title><![CDATA[How to Easily Add Share Links for Each Social Media Platform]]></title><description><![CDATA[In this tutorial, we'll go over how we can add a share link for each social media platform directly in our HTML.]]></description><link>https://blog.shahednasser.com/how-to-easily-add-share-links-for-each-social-media-platform/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e8d</guid><category><![CDATA[Beginners]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Fri, 19 Feb 2021 09:31:09 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/95bfddbd4607c75f613701832b636d57/photo-1554177255-61502b352de3.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/95bfddbd4607c75f613701832b636d57/photo-1554177255-61502b352de3.jpg" alt="How to Easily Add Share Links for Each Social Media Platform"/><p>Social media share links are important for every website, and you can add them very easily! In this tutorial, we'll go over how we can add a share link for each social media platform directly in our HTML.</p><hr><h3 id="twitter">Twitter</h3><p>To add a share link to Twitter:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://twitter.com/intent/tweet?text=Awesome%20Blog!&url=blog.shahednasser.com<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Share on Twiter<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span></code></pre></div><p>You can add the <code class="language-text">text</code> parameter for the text you want in the tweet and the <code class="language-text">url</code> parameter in case you want to add a URL to the tweet. You can test it here:</p><!--kg-card-begin: html--><a href="https://twitter.com/intent/tweet?text=Awesome%20Blog!&url=blog.shahednasser.com" target="_blank">Share on Twiter</a><!--kg-card-end: html--><p><em>Make sure to encode the text or the URL first. You can try it out online <a href="https://meyerweb.com/eric/tools/dencoder/">here</a>.</em></p><hr><h3 id="facebook">Facebook</h3><p>To add a share link to Facebook:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://www.facebook.com/sharer/sharer.php?u=blog.shahednasser.com&quote=Awesome%20Blog!<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Share on Facebook<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span></code></pre></div><p>The <code class="language-text">u</code> parameter is used to specify the link and the <code class="language-text">quote</code> parameter is used for the text. You can test it here: </p><!--kg-card-begin: html--><a href="https://www.facebook.com/sharer/sharer.php?u=blog.shahednasser.com&quote=Awesome%20Blog!" target="_blank">Share on Facebook</a><!--kg-card-end: html--><p><em>Make sure to encode the text or the URL first. You can try it out online <a href="https://meyerweb.com/eric/tools/dencoder/">here</a>.</em></p><hr><h3 id="whatsapp">Whatsapp</h3><p>To add a share link to Whatsapp:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://wa.me/?text=Awesome%20Blog!%5Cn%20blog.shahednasser.com<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Share on Whatsapp<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span></code></pre></div><p>For Whatsapp there's only a <code class="language-text">text</code> parameter so you can include both the text and the URL you want to send in it. Make sure to encode them first. You can test it here:</p><!--kg-card-begin: html--><a href="https://wa.me/?text=Awesome%20Blog!%5Cn%20blog.shahednasser.com" target="_blank">Share on Whatsapp</a><!--kg-card-end: html--><hr><h3 id="telegram">Telegram</h3><p>To add a share link to Telegram:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://t.me/share/url?url=blog.shahednasser.com&text=Awesome%20blog!<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Share on Telegram<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span></code></pre></div><p>You can include the text in the <code class="language-text">text</code> parameter and the URL in the <code class="language-text">url</code> parameter. You can test it here:</p><!--kg-card-begin: html--><a href="https://t.me/share/url?url=blog.shahednasser.com&text=Awesome%20blog!" target="_blank">Share on Telegram</a><!--kg-card-end: html--><p><em>Make sure to encode the text or the URL first. You can try it out online <a href="https://meyerweb.com/eric/tools/dencoder/">here</a>.</em></p><hr><h3 id="tumblr">Tumblr</h3><p>To share a link on Tumblr:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://www.tumblr.com/widgets/share/tool?canonicalUrl=blog.shahednasser.com&caption=Awesome%20blog!&tags=test%2Chello<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Share on Tumblr<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span></code></pre></div><p>For Tumblr, you need to add the <code class="language-text">canonicalUrl</code> parameter with the URL you want to share. Optionally, you can add <code class="language-text">caption</code> with the text you want to include in the post and <code class="language-text">tags</code> with the tags you want to include all comma-separated. You can test it here:</p><!--kg-card-begin: html--><a href="https://www.tumblr.com/widgets/share/tool?canonicalUrl=blog.shahednasser.com&caption=Awesome%20blog!&tags=test%2Chello" target="_blank">Share on Tumblr</a><!--kg-card-end: html--><p><em>Make sure to encode the text or the URL first. You can try it out online <a href="https://meyerweb.com/eric/tools/dencoder/">here</a>.</em></p><hr><h3 id="reddit">Reddit</h3><p>To share a link on Reddit:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://www.reddit.com/submit?url=blog.shahednasser.com&title=Awesome%20Blog!<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Share on Reddit<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span></code></pre></div><p>The <code class="language-text">url</code> parameter is for the URL you want to share and the <code class="language-text">title</code> parameter is for the title of the post. You can test it here:</p><!--kg-card-begin: html--><a href="https://www.reddit.com/submit?url=blog.shahednasser.com&title=Awesome%20Blog!" target="_blank">Share on Reddit</a><!--kg-card-end: html--><p><em>Make sure to encode the text or the URL first. You can try it out online <a href="https://meyerweb.com/eric/tools/dencoder/">here</a>.</em></p><hr><h3 id="linkedin">LinkedIn</h3><p>To share on LinkedIn:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://www.linkedin.com/sharing/share-offsite/?url=blog.shahednasser.com<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Share on LinkedIn<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span></code></pre></div><p>Just include the URL in the <code class="language-text">url</code> parameter. You can test it here:</p><!--kg-card-begin: html--><a href="https://www.linkedin.com/sharing/share-offsite/?url=blog.shahednasser.com" target="_blank">Share on LinkedIn</a><!--kg-card-end: html--><p><em>Make sure to encode the text or the URL first. You can try it out online <a href="https://meyerweb.com/eric/tools/dencoder/">here</a>.</em></p><hr><h3 id="gmail">Gmail</h3><p>To share by Gmail:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://mail.google.com/mail/u/0/?view=cm&to&su=Awesome+Blog!&body=https%3A%2F%2Fblog.shahednasser.com%0A&bcc&cc&fs=1&tf=1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Share by Gmail<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span></code></pre></div><p>The parameters you can use in Gmail:</p><p><code class="language-text">to</code>: the email you want the email to be sent to</p><p><code class="language-text">su</code>: The subject of the email</p><p><code class="language-text">body</code>: the content of the email</p><p><code class="language-text">bcc</code> and <code class="language-text">cc</code>: to set the bcc and cc of the email</p><p>All these parameters are optional. The only parameter that is required is <code class="language-text">view=cm</code> and you shouldn't change it. You can test it here:</p><!--kg-card-begin: html--><a href="https://mail.google.com/mail/u/0/?view=cm&to&su=Awesome+Blog!&body=https%3A%2F%2Fblog.shahednasser.com%0A&bcc&cc&fs=1&tf=1" target="_blank">Share by Gmail</a><!--kg-card-end: html--><p><em>Make sure to encode the text or the URL first. You can try it out online <a href="https://meyerweb.com/eric/tools/dencoder/">here</a>.</em></p><p> </p></hr></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[DEV VS Hashnode VS Medium: Where Should You Start Your Tech Blog]]></title><description><![CDATA[Where should you start your tech blog? Should you use DEV, Hashnode, or Medium? Or should you consider starting a personal blog of your own?]]></description><link>https://blog.shahednasser.com/dev-vs-hashnode-vs-medium-which-platform-should-you-use-for-your-blog/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e8c</guid><category><![CDATA[Tips]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 18 Feb 2021 11:33:29 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/9a4ab4291151d3b8e2d923983aebd763/photo-1519337265831-281ec6cc8514.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/9a4ab4291151d3b8e2d923983aebd763/photo-1519337265831-281ec6cc8514.jpg" alt="DEV VS Hashnode VS Medium: Where Should You Start Your Tech Blog"/><p>Let me start by saying that I recommend you start a tech blog. By sharing your knowledge and writing it down, you learn more. It also encourages you to try new things so that you can write about them as well. </p><p>But if you're here then you are probably already considering it. So where should you start your tech blog? Should you use <a href="https://dev.to/">DEV</a>, <a href="https://hashnode.com/">Hashnode</a>, or <a href="https://medium.com/">Medium</a>? Or should you consider starting a personal blog of your own, without using any of these platforms?</p><hr><h3 id="dev"><a href="https://dev.to/">DEV</a></h3><p>The charm of DEV, in my own experience, is the community. Everyone on DEV is respectful and encouraging. Whether you're a junior or a senior, you'll find your voice and place there. You can share experiences, tutorials, advice, or show off what you are learning. It's basically a "no judgment" space, which is great if you're still unsure about how to write or what to write about. </p><p>At DEV you'll also have a great source of traffic. Out of the three platforms, DEV drove the most traffic to my blog posts, and I think the reason behind that is simple yet very important: everyone is "featured" in a sense. In other platforms in general (not just the three mentioned here), veterans or big writers/bloggers might have their articles seen more. It would take you time to build your audience to then start having readers. However, with DEV, people can easily see your articles on their feed whether you have 0 followers or hundreds. The reason I find that important is that it gives everyone a chance to be heard.</p><p>I think DEV only has two drawbacks. The first is that you can't have your <em>own</em> blog on their platform, with your own name and customization, or with a subdomain or custom domain. The second is that their editor is fully in <a href="https://www.markdownguide.org/">Markdown</a>. So, if you're not familiar with it you might find it a hassle.</p><hr><h3 id="hashnode"><a href="https://hashnode.com/">Hashnode</a></h3><p>Hashnode is another great platform for blogging. Having a blog on Hashnode can be very similar to hosting your own personal blog. You can change the name, use a sub-domain or your custom domain, and customize the blog with so many options. You can change the colors, enable dark mode, enable newsletter opt-in for your blog visitors, and even allows integrations to Google Analytics, Hotjar, Facebook Pixel, and much more. You can almost do anything you would do in a personal blog with Hashnode.</p><p>Hashnode's editor is very easy to use. It also relies on Markdown, however, you also have a toolbar with options that you can use, so you don't really have to know Markdown to use it. The community at Hashnode is similar to that at DEV which is also a plus.</p><p>However, from my own experience, it's not easy to get much traffic in Hashnode. I'm not sure if it's because your articles aren't shown often in people's feed or which reason it is exactly, but you wouldn't generate the same kind of traffic you would at DEV. On the other side, writing on Hashnode can get you featured on <a href="https://daily.dev/">daily.dev</a> which can get people to see your article more. </p><hr><h3 id="medium"><a href="https://medium.com/">Medium</a></h3><p>Medium is probably the most famous out of the three, and not just in the technical world. Medium is a big platform that offers an easy-to-use editor, your own blog with a subdomain or a custom domain, customization to your blog from colors to the look and feels in general, and newsletter opt-in to your visitors. </p><p>Getting traffic on Medium, however, is tough. Medium prioritizes articles from big blogs on their platform or authors who are enrolled in their <a href="https://medium.com/earn">Partner Program</a>. If you're neither, your articles probably won't be seen much by anyone. Another way people can see your articles is if you submit your publication to another big blog, meaning that your article appears as part of another blog, but this requires a special invite from the blog itself so that you can submit your publications. I personally have been submitting mine for <a href="https://levelup.gitconnected.com/">gitconnected</a>'s Level Up Coding blog as I have been invited as an author on it before, and that's how I mainly get traffic on it.</p><p>Another thing is that on Medium you don't really have much interaction with others in the community. Generally, readers on Medium just read your article, and if they like it enough they'll give it "claps", but not much interaction happens (at least from my own experience).</p><hr><h3 id="should-you-start-a-personal-blog">Should You Start A Personal Blog?</h3><p>Starting a personal blog definitely gives you more freedom. However, depending on the kind of CMS platform or blogging experience you are going for, there are setups and costs that you need to consider. Especially if you're still a beginner, you might find it hard to manage your own hosting. </p><p>Personal blogs have a big perk which is you have a better chance at monetizing them, but even that can take some time as it is not easy. </p><p>If you are interested in starting your own blog and you're looking for ways to do that cost-free, here are some suggested reads you can look through:</p><ol><li><a href="https://blog.shahednasser.com/the-things-you-can-do-for-free-the-ultimate-guide/">The Things You Can Do For Free: The Ultimate Guide</a></li><li><a href="https://blog.shahednasser.com/deploy-a-website-with-jekyll-and-github-pages">Deploy a Free Website With Jekyll and GitHub Pages</a></li></ol><hr><h3 id="conclusion">Conclusion</h3><p>All 3 platforms are great choices. It mostly depends on what kind of blogging experience you are going for. </p><ol><li>If you're looking for a place where you can write freely and also interact with others in the community, start at <a href="https://dev.to/">DEV</a>. </li><li>If you're looking for a place where you can also do that with less traffic, but have more freedom, go for <a href="https://hashnode.com/">Hashnode</a>. </li><li>If you're looking for a platform where you can write easily and also have some freedom in your blog, go for <a href="https://medium.com/">Medium</a>.</li></ol></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Here Are Some GitHub Repos I've Starred Throughout The Years]]></title><description><![CDATA[A list of GitHub Repositories that I've starred throughout the years. Some are helpful, others are just nice to know about.]]></description><link>https://blog.shahednasser.com/github-repos-starred/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e8b</guid><category><![CDATA[Open Source]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 16 Feb 2021 14:20:15 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/886dbe3bdf7a7567b6d417dc0f63e95f/photo-1556075798-4825dfaaf498.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/886dbe3bdf7a7567b6d417dc0f63e95f/photo-1556075798-4825dfaaf498.jpg" alt="Here Are Some GitHub Repos I've Starred Throughout The Years"/><p>Throughout the years, I have found repositories that I liked and starred (then totally forgot about, to be honest). Some are very helpful, others are just nice to know about. So, I decided to put some of them on a list in the hopes that it helps others.</p><hr><h3 id="front-end-checklist"><a href="https://github.com/thedaviddias/Front-End-Checklist">Front-End Checklist</a></h3><p>The name is pretty straightforward. This repository gives you the ultimate checklist you might need for your front-end projects. It is very detailed and I think it's extremely helpful for beginners and for the rest of us that tend to look over or forget certain details sometimes.</p><hr><h3 id="node-js-best-practices"><a href="https://github.com/goldbergyoni/nodebestpractices">Node.js Best Practices</a></h3><p>This repositories include articles and news that highlight the best practices of Node.js. It's constantly updated and insightful. So, if you're interested in Node.js I suggested you go through the list to learn more about its best practices.</p><hr><h3 id="magictools"><a href="https://github.com/ellisonleao/magictools">magictools</a></h3><p>magictools is a repository that lists resources you might need for game development. This ranges from graphics to code and audio. It also specifies whether the resources are free, open-source, paid, or partially-free. I recommend this for game developers in general.</p><hr><h3 id="carbon"><a href="https://github.com/carbon-app/carbon">Carbon</a></h3><p>Do you ever see on social media beautifully designed code screenshots and think "hmm I wonder how they make those?" The answer is Carbon. Carbon lets you share and create beautifully designed code images. You can do this using their <a href="https://carbon.now.sh/">website</a> by choosing the language, typing in your code, and then export the image and share it to any social media platform you want. It also has many features as well so I suggest you check out their GitHub repositories for more details.</p><hr><h3 id="awesome-design-tools"><a href="https://github.com/goabstract/Awesome-Design-Tools">Awesome Design Tools</a></h3><p>This repository contains a huge list of websites where you can find design resources and use them for free. It does not just include design resources, but also resources that will be helpful for your front-end development as well. It can save you some time when you need some resources for your next project.</p><hr><h3 id="lax-js"><a href="https://github.com/alexfoxy/lax.js">lax.js</a></h3><p>lax.js is a library you can use to develop beautiful animations on scroll. It's a nice, lightweight library that will help you create beautiful and modern websites, hassle-free.</p><hr><h3 id="public-apis"><a href="https://github.com/n0shake/Public-APIs">Public-APIs</a></h3><p>This repository includes a list of all kinds of APIs you can use either completely for free or with a free trial. The APIs can be used in a variety of projects. From Data Science APIs to Dictionary APIs, you can find them all in this list.</p><hr><h3 id="build-your-own-x"><a href="https://github.com/danistefanovic/build-your-own-x">build-your-own-x</a></h3><p>Ever wondered how to build your own Gameboy emulator? How about rebuilding GIT? A huge list of the things you can build is on this repository. It has a variety of programming languages and things you can build with those programming languages. I recommend checking it out and practicing a programming language through it.</p><hr><h3 id="free-for-dev"><a href="https://github.com/ripienaar/free-for-dev">free-for-dev</a></h3><p>If you want to start and deploy your next project, but you don't really want to pay or you're controlling your budget, then I suggest keeping this repository in your Stars. This repository provides a full list of services you can find online that will provide you with what you need to do for free.</p><p><em>Suggested Read: <a href="https://blog.shahednasser.com/the-things-you-can-do-for-free-the-ultimate-guide/">The Things You Can Do For Free: The Ultimate Guide</a></em></p><hr><h3 id="not-paid"><a href="https://github.com/kleampa/not-paid">not-paid</a></h3><p>This repository might be helpful to some freelancers. If you worked on a project and the client isn't paying you, just add the <code class="language-text">js</code> file in this repository to the web page and it will add opacity to the page then increase it every day until the page completely fades away. </p><hr><h3 id="conclusion">Conclusion</h3><p>These are some of the GitHub repositories I've liked throughout my years as a developer. If you have others as well, please share them in the comments!</p></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[I Created Famous Logos with CSS]]></title><description><![CDATA[I decided to take on a challenge to use CSS to create famous logos we see every day to practice CSS in a new light.]]></description><link>https://blog.shahednasser.com/i-created-famous-logos-with-css/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e8a</guid><category><![CDATA[CSS]]></category><category><![CDATA[My Experience]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 15 Feb 2021 14:44:11 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/c876345872dba898f90e87430b458e9d/photo-1579869847557-1f67382cc158.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/c876345872dba898f90e87430b458e9d/photo-1579869847557-1f67382cc158.jpg" alt="I Created Famous Logos with CSS"/><p>CSS is a powerful tool that can do almost anything once you have had a full grasp of it. Sometimes we're not aware of all the things you can do with CSS, and end up taking a complicated route to do what we need to be done. That's why we need to always practice CSS and grow our skills in it and knowledge of it.</p><p>I decided to take on a challenge to use CSS to create famous logos we see every day. It was a challenge that helped me think better in CSS and understand what means I can use to achieve the expected result.</p><p>I'll list the logos from the least difficult to the most difficult for me. You can check out the entire collection on <a href="https://codepen.io/collection/ABrgEg">CodePen</a>.</p><hr><h3 id="google">Google</h3><p>This one's concept is pretty simple. We have the letters of Google in different colors, and that's mostly it. However, there was one problem which is the font. Google uses a custom font for the logo called <a href="https://fontmeme.com/google-new-logo-font/#:~:text=About%20Google%20New%20Logo%20Font&text=The%20new%20Google%20logotype%20is,old%20style%20serif%20typeface%20Catull.">Product Sans</a>, so I had to resort to what looked the closest to it from Google Fonts, and I choose <a href="https://fonts.google.com/specimen/Poppins">Poppins</a>.</p><!--kg-card-begin: html--><p class="codepen" data-height="460" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="RwoozNK" style="height: 460px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Google"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/RwoozNK"> Google</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><hr><h2 id="youtube">Youtube</h2><p>This was another easy one. It was a box with a triangle inside essentially. However, I had some trouble with making the rounded borders similar to the logo and had to settle for the next closest thing.</p><!--kg-card-begin: html--><p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="gOLmwEE" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Youtube"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/gOLmwEE"> Youtube</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><hr><h3 id="facebook">Facebook</h3><p>My problem with the Facebook logo was similar to that of Google; I couldn't use the same font as it is a custom font, so I had to use <a href="https://fonts.google.com/specimen/Prompt">Prompt</a> as the f letter looked the most similar to the one in Facebook's logo.</p><!--kg-card-begin: html--><p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="bGBqeoL" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Facebook"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/bGBqeoL"> Facebook</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><hr><h3 id="instagram">Instagram</h3><p>The concept of the logo is simple in Instagram, however, the gradient was a little bit tough. I had to use the help of the internet as well to get it right, but it was a nice take on gradients and seeing what more can be done with it. I haven't really used gradients heavily before and all of my uses of it were pretty simple, so it was a good practice.</p><!--kg-card-begin: html--><p class="codepen" data-height="333" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="JjbWRNN" style="height: 333px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Instagram"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/JjbWRNN"> Instagram</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><hr><h3 id="whatsapp">Whatsapp</h3><p>This one was interesting. So, as I was doing the entire logo in CSS I had to also make the phone shape in the middle with CSS as well. The problem that I had was that I couldn't figure out how to make the left side of the phone as rounded as it is in the logo. Usually, we use rounded corners a lot which are easy to make, but I've never really tried making sort of an arc shape in CSS.</p><p>So I searched online and I came upon the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-left-radius">border-bottom-left-radius</a> property, which I already knew. However, one thing I probably learned as a beginner but totally forgot about now is that this property can take two values, one for length and one for percentage. The length determines the size of the circle radius or the semi-major and semi-minor axes of the ellipses, whereas the percentage is of the width or height of the box(or element). The first value is for the horizontal axis whereas the second part is for the vertical axis. This property has 4 variations to achieve the same to all 4 sides of the element.</p><p>After learning this, I was able to make the phone shape look better and I applied this as well to other logos I worked on. I never really tried using this property before so I still need more practice with it.</p><!--kg-card-begin: html--><p class="codepen" data-height="428" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="ExNWNJO" style="height: 428px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Whatsapp"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/ExNWNJO"> Whatsapp</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><hr><h3 id="twitter">Twitter</h3><p>This one was so frustrating to do and took the longest. I had to leave it at some point and come back to it later. Although it may not look perfect, I'm still really proud of it.</p><p>I had to rely a lot on <code class="language-text">:after</code> and <code class="language-text">:before</code> pseudo-elements and the border-radius property I learned with Whatsapp. I mostly needed to learn to look outside the box. I broke down the Twitter bird shape into 4 sections and worked my way through it. Although it was frustrating at some points, it was a needed practice not just for my skills in CSS, but also for my creativity as a developer.</p><!--kg-card-begin: html--><p class="codepen" data-height="329" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="rNWWXmj" style="height: 329px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Twitter"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/rNWWXmj"> Twitter</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><hr><h3 id="conclusion">Conclusion</h3><p>I will do part 2 of this challenge and take on other famous logos. If you have ideas for logos that would present a good challenge, leave them in the comments! I also encourage you to take on similar challenges as it is a nice break from the same old and a good way to learn or relearn what we knew but forgot about.</p></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Awesome Resources: Resources added by the community for the community]]></title><description><![CDATA[Awesome Resources is a list of helpful resources added by the community for the community, ranging from topics about programming to general topics.]]></description><link>https://blog.shahednasser.com/awesome-resources/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e89</guid><category><![CDATA[Projects]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sun, 14 Feb 2021 15:04:25 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/f4be41e3e585cd9523ffda0841932980/photo-1520076794559-6a1229412a42.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/f4be41e3e585cd9523ffda0841932980/photo-1520076794559-6a1229412a42.jpg" alt="Awesome Resources: Resources added by the community for the community"/><p>As you probably know, October is when Hacktoberfest happens. Every year in October, Developers all around the world participate in this event to participate in open source projects, and receive good swag.</p><p>However, not everyone is able to help big projects, and a lot of people resort to smaller and simple projects. Also, I wanted to create a project that would be helpful long after Hacktoberfest. That's when I started my project <a href="https://github.com/shahednasser/awesome-resources">Awesome Resources</a>.</p><hr><h3 id="purpose">Purpose</h3><p>The idea of this repository was simple. Participate in Hacktoberfest by adding any helpful resources you know of that is related to Programming or educational in general. The reason behind that is it would accumulate a list of helpful and insightful resources for every language or topic that others in the community can easily find in one place. </p><hr><h3 id="contributions">Contributions</h3><p>So many people in the community have contributed by adding links to articles, videos, tutorials, or any helpful links about different topics. The topics ranged from programming related like Javascript, Ruby, and Android development, to general and different topics like Graph Theory, Linear Algebra, and Ethical Hacking.</p><p>The contribution and the project was simple. Just add the link to the <a href="https://github.com/shahednasser/awesome-resources/blob/master/README.md">README </a>and submit a PR. If the topic you were adding to already exists, add the resource to the end of the list. If not, then add a new topic. The more people participated and contributed, the more the list of topics grew.</p><p>By the end of Hacktoberfest, there were 47 topics that had resources in them. Those resources would hopefully be of help to others, thanks to the community!</p><hr><h3 id="progress-after-hacktoberfest">Progress After Hacktoberfest</h3><p>After Hacktoberfest, I decided to turn Awesome Resources into a <a href="https://shahednasser.github.io/awesome-resources/">website</a> as well. I built the website with <a href="https://jekyllrb.com/">Jekyll</a>, which was my first time using it. As it was new to me, it was a good way for me to learn it and learn more about Ruby environment as well (even if it's just the basics). </p><p>With Jekyll, the content that is in the README is automatically added to the website even when updated later on, as you can use markdown in Jekyll. All that was needed was to add simple styling to the website.</p><p><strong>Suggested Read</strong>: If you want to learn how to create a website with Jekyll, you can check out my tutorial <a href="https://blog.shahednasser.com/deploy-a-website-with-jekyll-and-github-pages/">here</a>.</p><hr><h3 id="conclusion">Conclusion</h3><p>If you're a beginner and you're looking for helpful resources in different topics, please have a look at <a href="https://shahednasser.github.io/awesome-resources/">Awesome Resources</a>, as it can be helpful. If you also have resources that you find helpful for others and want to share them, or you have good ideas on how to improve it to make it more helpful for others, please <a href="https://github.com/shahednasser/awesome-resources">contribute to it</a>.</p></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Keep Your Javascript Projects Secure With Snyk]]></title><description><![CDATA[It's important you keep your Javascript projects secure, especially with all the NPM packages you might be using. This is where Snyk comes in.]]></description><link>https://blog.shahednasser.com/keep-your-projects-secure-with-snyk/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e88</guid><category><![CDATA[Javascript]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 13 Feb 2021 16:42:32 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/2cb0a349eeaaa7b2513ed0e9b578caf3/photo-1593720218746-e13e4a422a3b.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/2cb0a349eeaaa7b2513ed0e9b578caf3/photo-1593720218746-e13e4a422a3b.jpg" alt="Keep Your Javascript Projects Secure With Snyk"/><p>It's important you keep your Javascript projects secure, especially with all the NPM packages you might be using, and their own dependencies that so many developers don't look into.</p><p>A lot of times, your dependencies (or your dependencies' dependencies) might have security issues in a certain version. A lot of times it gets fixed in the next version, but if you don't act on updating your dependencies accordingly, then your project could be in danger to an attack of some kind (depending on the security issue).</p><p>It can be harder when it's the dependencies' dependencies. You might not know of a dependency in your project and that dependency's version could be insecure due to an exploit. Keeping up with your dependencies, or sometimes knowing how to fix them, can be a hassle.</p><p>One way is you can leverage NPM's <code class="language-text">audit</code> command. However, sometimes you might find it hard to resolve the issue, or you might not know about an exploit in the versions you currently have and forget to check your project. This is where services like <a href="https://snyk.io/">Snyk </a>come in.</p><hr><h3 id="what-is-snyk">What is Snyk</h3><p><a href="https://snyk.io/">Snyk </a>is a platform that ensures your projects security, generally. It has a lot of services, and one of them is <a href="https://snyk.io/product/open-source-security-management/">Snyk Open Source</a>, which provides security management to open source projects. This service is free to use.</p><p>Through Snyk Open Source, you can track any repository you have, be informed of any exploits and vulnerabilities, and learn how to resolve them. </p><hr><h3 id="usage">Usage</h3><p>First, you need to <a href="https://app.snyk.io/login">create an account</a>. You can create an account with GitHub, BitBucket, Google or other platforms as well. If you have repositories on GitHub or BitBucket and you want to track their security, then I suggest creating an account with one of them as you will give them immediate access to your repositories on account creation.</p><p>Once you create an account, if you gave access to your repositories, then you will get to choose which ones you want Snyk to manage its security. The entire list will be shown to you, so you can easily choose among them.</p><p>After you are done setting up your account, you will see your dashboard, where you will see the pending tasks regarding exploits and security issues in your projects that need to be resolved.</p><p>If you open a project, you can see all the issues in your project. All issues have 3 levels of severities: High, Medium and Low.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/shahednasser-my-blog-package-json-Snyk.png" class="kg-image" alt="Keep Your Javascript Projects Secure With Snyk" loading="lazy"/></figure><p>For each issue, you can see its severity, type of exploit, which package is causing it, which version is the exploit caused by and if there is a version that fixes the exploit, and the path that the exploit originated one. This last one is very helpful when the exploit is in a dependency of other dependencies.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/snyk-1.png" class="kg-image" alt="Keep Your Javascript Projects Secure With Snyk" loading="lazy"/></figure><p>If you also click on "More about this issue" at the bottom of the issue, you can see more information about the security issue caused, what the attack can cause, and how to resolve the issue. If the issue can be easily resolved, you will also have the option to create a PR right from the interface, which makes it even easier. You can see many other information about the exploit as well.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/snyk-2.png" class="kg-image" alt="Keep Your Javascript Projects Secure With Snyk" loading="lazy"/></figure><p>This way you can either use their "PR Fix" if it's available, or learn how you can resolve it yourself by looking at the "Remediation" and the path of the exploit. </p><p>Once you have fixed the issue, you can click on "Retest now" in the project's page and see if the issue is now resolved.</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/snyk-3.png" class="kg-image" alt="Keep Your Javascript Projects Secure With Snyk" loading="lazy"/></figure><h3 id="email-notifications">Email Notifications</h3><p>Another great feature is that once Snyk finds a vulnerability in your project, it will send you an Email about it. That way you can always stay updated about vulnerabilities and learn how to resolve them as soon as possible.</p><hr><h3 id="conclusion">Conclusion</h3><p>There are a lot of services out there that helps you keep your projects secure not just Snyk. It's very important to use one of them to make sure your projects are never using dependencies that can cause your project to be exploited.</p></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Chrome Extension Tutorial: Migrating to Manifest V3 from V2]]></title><description><![CDATA[See the detailed steps you need to take to migrate your extension from Manifest V2 to Manifest V3]]></description><link>https://blog.shahednasser.com/chrome-extension-tutorial-migrating-to-manifest-v3-from-v2/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e87</guid><category><![CDATA[Browser Extensions]]></category><category><![CDATA[Javascript]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 11 Feb 2021 11:36:42 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/980b514c3d5e977ce079df016fc66a17/photo-1554306274-f23873d9a26c-min.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/980b514c3d5e977ce079df016fc66a17/photo-1554306274-f23873d9a26c-min.jpg" alt="Chrome Extension Tutorial: Migrating to Manifest V3 from V2"/><p>In November 2020, Chrome introduced Manifest V3. For a long time, extensions have been using Manifest V2, so this is a big transition, especially with the new features in V3.</p><p>In this tutorial, we will see the steps needed to go from Manifest V2 to V3. I will be using the extension from a previous tutorial (<a href="https://blog.shahednasser.com/chrome-extension-tutorial-replace-images-in-any-website-with-pikachu/">Chrome Extension Tutorial — Replace Images in Any Website with Pikachu</a>) with a new branch. If you're not familiar with it, we built a chrome extension that replaces all images in a website with random Pikachu images that we retrieved through an API. You can checkout the repository <a href="https://github.com/shahednasser/pikachu-everywhere/tree/manifest-v3">here</a>.</p><hr><h3 id="why-migrate-to-manifest-v3">Why Migrate to Manifest V3?</h3><p>As Chrome's <a href="https://developer.chrome.com/docs/extensions/mv3/intro/">Documentation</a> puts it:</p><blockquote>Extensions using MV3 will enjoy enhancements in security, privacy, and performance; they can also use more contemporary Open Web technologies adopted in MV3, such as service workers and promises.</blockquote><hr><h2 id="changes-to-manifest-json">Changes to manifest.json</h2><h3 id="changing-the-version">Changing the Version</h3><p>The first obvious step is that you need to change the version of your manifest. In your manifest.json file, change it as follows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> ...<span class="token punctuation">,</span> <span class="token property">"manifest_version"</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span></code></pre></div><p>If you try to add your extension to chrome now (or reload it if it's already there), you'll see different errors regarding changes that you still need to make to your manifest.json file.</p><h3 id="host-permissions">Host Permissions</h3><p>In Manifest V2, there were two ways to get permission for your apis or any host you will need to make requests to from the extension: either in the <code class="language-text">permissions</code> array or in the <code class="language-text">optional_permissions</code> array.</p><p>In Manifest V3, all host permissions are now separate in a new array with the key <code class="language-text">host_permissions</code>. Host permissions should not be added with other permissions anymore.</p><p>Going back to our example, this was our <code class="language-text">permissions</code> array:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> ...<span class="token punctuation">,</span> <span class="token property">"permissions"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"https://some-random-api.ml/*"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span></code></pre></div><p>Now, it should change to this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> ...<span class="token punctuation">,</span> <span class="token property">"host_permissions"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"https://some-random-api.ml/*"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span></code></pre></div><p>In our case, we just needed to change the key from <code class="language-text">permissions</code> to <code class="language-text">host_permissions</code>. However, if your extension has other values in <code class="language-text">permissions</code>, then you should keep them in it and just move your host permissions to <code class="language-text">host_permissions</code>.</p><h3 id="background-scripts">Background Scripts</h3><p>Manifest V3 replaces background scripts with service workers. We'll talk about how to make the transition in a bit, but first the transition need to be made in manifest.json.</p><p>The <code class="language-text">background</code> object currently looks like this in our extension:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> ...<span class="token punctuation">,</span> <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"assets/js/background.js"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"persistent"</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span></code></pre></div><p>What we need to do is change the <code class="language-text">scripts</code> array key to <code class="language-text">service_worker</code>, and now you should have one service worker instead of multiple background pages or scripts. So, it should look like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> ...<span class="token punctuation">,</span> <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"service_worker"</span><span class="token operator">:</span> <span class="token string">"assets/js/background.js"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span></code></pre></div><p>Note that we don't need to add <code class="language-text">persistent</code> anymore. Also, if you have <code class="language-text">page</code> inside <code class="language-text">background</code>, that should be changed to a service worker as well.</p><h3 id="actions">Actions</h3><p>Actions used to be <code class="language-text">browser_action</code> and <code class="language-text">page_action</code>, but now they're unified into <code class="language-text">action</code> in Manifest V3. This is due to the fact that over time they became similar, and separating them became unnecessary. </p><p>We don't use it in our extension, but this is an example of how it should be like:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> ...<span class="token punctuation">,</span> <span class="token property">"action"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">//include everything in browser_action</span> <span class="token comment">//include everything in page_action</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span></code></pre></div><p>There are also changes in the code needed, we will get to that later.</p><h3 id="content-security-policy">Content Security Policy</h3><p>Again, this is not used in our extension, but we still need to go over it. If your extension had a Content Security Policy (CSP), then you need to change it from a string (the way it was in Manifest V2) to an object (the way it is in Manifest v3).</p><p>An example of how it should be like in Manifest V3:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> ...<span class="token punctuation">,</span> <span class="token property">"content_security_policy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"extension_pages"</span><span class="token operator">:</span> <span class="token string">"..."</span><span class="token punctuation">,</span> <span class="token property">"sandbox"</span><span class="token operator">:</span> <span class="token string">"..."</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span></code></pre></div><h3 id="web-accessible-resources">Web-Accessible Resources</h3><p>The last change you need to make in the manifest.json is changing the <code class="language-text">web_accessible_resources</code> array to an object detailing all the resources. Here's an example of how it should be like in V3:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> ...<span class="token punctuation">,</span> <span class="token property">"web_accessible_resources"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"resources"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token comment">//the array of resources you had before</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span></code></pre></div><p>The object also will support in future releases the keys <code class="language-text">matches</code>(array of URLs), <code class="language-text">extension_ids</code>(array of keys), and <code class="language-text">use_dynamic_url</code>(boolean).</p><h3 id="adding-the-extension">Adding the Extension</h3><p>Now if you go to <a href="chrome://extensions">chrome://extensions</a> in your browser and add your extension or reload it, it will change to a Manifest V3 extension successfully. However, in our case it will show you an error button in the extension box, and when you click it, it will say "service worker registration failed." That's because there's still more work to do in our code.</p><hr><h2 id="from-background-scripts-to-service-workers">From Background Scripts to Service Workers</h2><p>First, what are service workers and what's the difference between them and background scripts?</p><p>Background scripts are essential in almost all extensions. They allow you to do some actions or execute code without the need for the user to open a certain page or do something. This can be used to send notifications, manage communication with content scripts, and much more. Background scripts are generally always running in the background.</p><p>Service workers are executed when needed. Unlike background scripts, they are not always running in the background. At the top level, service workers should register listeners to some events that would allow them later on to be executed.</p><p>The shift from background scripts to service workers depends on your code in extension. Some extensions might need a lot of reworking, while others not so much.</p><p>The first step you need to do is move your file that was previously a background script or page to the root of the extension. This is actually why in our extension we received the error stating that the registration of the service worker failed. Our background script's path was <code class="language-text">js/assets/background.js</code> relative to the root of our extension.</p><p>If your case is similar, move your background script to the root of your extension, then change the value of <code class="language-text">service_worker</code> in your manifest to reflect the change:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> ...<span class="token punctuation">,</span> <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"service_worker"</span><span class="token operator">:</span> <span class="token string">"background.js"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span></code></pre></div><p>If you reload the extension, the service worker should register successfully.</p><p>Now, let's look at the code. In our extension, our background script looked as follows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript">chrome<span class="token punctuation">.</span>runtime<span class="token punctuation">.</span>onMessage<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">message<span class="token punctuation">,</span> sender<span class="token punctuation">,</span> senderResponse</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>message<span class="token punctuation">.</span>msg <span class="token operator">===</span> <span class="token string">"image"</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'https://some-random-api.ml/img/pikachu'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">response</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">data</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">let</span> dataObj <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">senderResponse</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">data</span><span class="token operator">:</span> dataObj<span class="token punctuation">,</span> <span class="token literal-property property">index</span><span class="token operator">:</span> message<span class="token punctuation">.</span>index<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">error</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"error"</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token comment">// Will respond asynchronously.</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Basically our background script listened to a message using <code class="language-text">chrome.runtime.onMessage.addListener</code>, and if the message was asking for an image, it would send a request to the API, and then return the data to our content script.</p><p>Our background script actually does not need any additional change. The reason behind that is that the background script that is now a service worker just registers an event listener and executes code when that event occurs, which is exactly what a service worker should be doing.</p><p>However, not all extensions are like that as there are different use cases. Here's what you need to check for and amend in your background script:</p><h3 id="global-variables">Global Variables</h3><p>As stated above, background scripts previously were always running in the back. Meaning if I had the following code:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> count <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> chrome<span class="token punctuation">.</span>runtime<span class="token punctuation">.</span>onMessage<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token parameter">message</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> count<span class="token operator">++</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>count<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Each time the background script received a message, the count would increment. So, at first it would be 0, then 1, then 2, and so on.</p><p>In service workers, this will not work anymore. Service workers will run only when they need to, and terminate when they've finished their job. So, the above code would always print in the console "1".</p><p>Changing this depends on your use case. In the above example, the count could be passed back and forth between your background script and content script to get the result needed. An even better way would be to use Chrome's Storage API. </p><p>Using that, the code will look something like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript">chrome<span class="token punctuation">.</span>runtime<span class="token punctuation">.</span>onMessage<span class="token punctuation">.</span><span class="token function">addListener</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token parameter">message</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> chrome<span class="token punctuation">.</span>storage<span class="token punctuation">.</span>local<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">"count"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">result</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> count <span class="token operator">=</span> result<span class="token punctuation">.</span>count <span class="token operator">?</span> result<span class="token punctuation">.</span>count<span class="token operator">++</span> <span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">;</span> chrome<span class="token punctuation">.</span>storage<span class="token punctuation">.</span>local<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token punctuation">{</span>count<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>count<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Again, it depends on your code, so make sure to make the changes based on what's best for you.</p><h3 id="timers-and-alarms">Timers and Alarms</h3><p>Timers were used in background scripts with no problems as they are always running in the background. However, this will not work in service workers. You should replace all timers with the <a href="https://developer.chrome.com/docs/extensions/reference/alarms/">Alarms API</a>.</p><h3 id="accessing-the-dom">Accessing the DOM</h3><p>Service workers do not have access to windows or the DOM. If your extension needs that, you can use libraries like <a href="https://github.com/jsdom/jsdom">jsdom</a> or use <a href="https://developer.chrome.com/docs/extensions/reference/windows#method-create">chrome.windows.create</a> and <a href="https://developer.chrome.com/docs/extensions/reference/tabs#method-create">chrome.tabs.create</a>. It depends on your usage and what fits your needs.</p><p>This is also needed if your background scripts record audio or video, as that is not possible in service workers.</p><h3 id="creating-canvas">Creating Canvas</h3><p>If your background script previously created canvas, you can still do that with the <a href="https://html.spec.whatwg.org/multipage/canvas.html#the-offscreencanvas-interface">OffscreenCanvas</a> API. All you have to do is replace <code class="language-text">document</code> with <code class="language-text">OffscreenCanvas</code>.</p><p>For example, if this was your code:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> canvas <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'canvas'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Then you should change it to:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> canvas <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">OffscreenCanvas</span><span class="token punctuation">(</span>width<span class="token punctuation">,</span> height<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h3 id="checking-your-extension">Checking Your Extension</h3><p>After you are done with making the changes need to change your background script to a service worker, reload your extension in the browser to see if it is working properly.</p><p>In our case, there was no change needed in <code class="language-text">background.js</code> other than moving it to the root. So, if you reload the extension and go to a page, you will find that images have been replaced with Pikachu images successfully.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/pikachu-github.png" class="kg-image" alt="Chrome Extension Tutorial: Migrating to Manifest V3 from V2" loading="lazy"/></figure><hr><h3 id="actions-api">Actions API</h3><p>As mentioned before, <code class="language-text">browser_action</code> and <code class="language-text">page_action</code> are now merged into <code class="language-text">action</code>. The same should be applied in your code. If you are using <code class="language-text">browserAction</code> or <code class="language-text">pageAction</code> like below:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript">chrome<span class="token punctuation">.</span>browserAction<span class="token punctuation">.</span>onClicked<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token parameter">tab</span> <span class="token operator">=></span> <span class="token punctuation">{</span> … <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> chrome<span class="token punctuation">.</span>pageAction<span class="token punctuation">.</span>onClicked<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token parameter">tab</span> <span class="token operator">=></span> <span class="token punctuation">{</span> … <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>It should be changed to use the new Actions API as follows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript">chrome<span class="token punctuation">.</span>action<span class="token punctuation">.</span>onClicked<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span><span class="token parameter">tab</span> <span class="token operator">=></span> <span class="token punctuation">{</span> … <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>So, make sure to replace all <code class="language-text">browserAction</code> and <code class="language-text">pageAction</code> usages with <code class="language-text">action</code>.</p><hr><h2 id="executescript">executeScript</h2><p>If your code executed arbitrary strings using executeScript's <code class="language-text">code</code> property, you have two ways to change it. Also, instead of using <code class="language-text">chrome.tabs.executeScript</code>, you need to replace <code class="language-text">tabs</code> with <code class="language-text">scripting</code> so that it will be <code class="language-text">chrome.scripting.executeScript</code>.</p><h3 id="moving-the-code-to-a-new-file">Moving the Code To a New File</h3><p>You need to move the value of <code class="language-text">code</code> to a new file and use executeScript's <code class="language-text">file</code> property.</p><p>For example, if your code had something like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript">chrome<span class="token punctuation">.</span>tabs<span class="token punctuation">.</span><span class="token function">executeScript</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">code</span><span class="token operator">:</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Hello, World!"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>You should move the value of <code class="language-text">code</code>, which here is <code class="language-text">alert("Hello, World!")</code> to a new file (let's call it <code class="language-text">hello-world.js</code>):</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Hello, World!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Then change your previous code to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript">chrome<span class="token punctuation">.</span>scripting<span class="token punctuation">.</span><span class="token function">executeScript</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">file</span><span class="token operator">:</span> <span class="token string">'hello-world.js'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><h3 id="put-the-code-in-a-function">Put the Code in a Function</h3><p>If your code can be put in a function instead, like the example code, then just move it to a function in the same file, then assign the <code class="language-text">function</code> property of <code class="language-text">executeScripts</code> to the function you created:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">greeting</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Hello, World!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> chrome<span class="token punctuation">.</span>scripting<span class="token punctuation">.</span><span class="token function">executeScript</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token keyword">function</span><span class="token operator">:</span> greeting <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><hr><h3 id="additional-work">Additional Work</h3><p>There is a list of other changes and things you need to look for in your code:</p><ol><li>If your extension uses the webRequest API, which is typically used in an enterprise setting where the extension is forced-installed, you need to replace it with the <a href="https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/">declarativeNetRequest</a> API.</li><li>If you are making any CORS requests in your content scripts, make sure to move them to your service worker.</li><li>Remotely-hosted code is not allowed anymore. You need to find another way to execute your remotely hosted code. Chrome's documentation suggests using either <strong>Configuration-driven features and logic </strong>which means you retrieve a JSON file with the configuration needed and you cache it locally for later use, or <strong>Externalize logic with a remote service </strong>which means you have to move your application logic from your extension to a remote web service.</li><li>Check the <a href="https://developer.chrome.com/docs/extensions/reference/">API Reference</a> for any deprecated APIs or methods you might be using.</li></ol></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[The Things You Can Do For Free: The Ultimate Guide]]></title><description><![CDATA[When creating any kind of project, there will be costs that you have to handle. Here are a list of tools and services you can use for free.]]></description><link>https://blog.shahednasser.com/the-things-you-can-do-for-free-the-ultimate-guide/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e86</guid><category><![CDATA[Tips]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 10 Feb 2021 11:35:00 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/032b0a41b26e3c4c024bfafaffe21cda/photo-1546900703-cf06143d1239.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/032b0a41b26e3c4c024bfafaffe21cda/photo-1546900703-cf06143d1239.jpg" alt="The Things You Can Do For Free: The Ultimate Guide"/><p>When creating any kind of project, there will be costs that you have to handle. Whether big or small, at some point it can be hindering or cause a hassle. </p><p>I will list for you different topics you might need in your projects and how you can get it for free.</p><hr><h3 id="hosting">Hosting</h3><p>Finding a hosting is one of the most troublesome parts when you are creating a project, especially when you need it for free. Here's a list of services or websites that offer free hosting, and what kind of projects you can use them for:</p><ol><li><strong><a href="https://www.netlify.com/">Netlify</a>: </strong>Netlify is perfect for static websites like portfolios. It also supports <a href="https://www.netlify.com/jamstack/">Jamstack</a>, which basically decouples the backend from the frontend, allowing your website to be deployed directly to a CDN. This helps make your website faster and more secure. You can use this to create, for example, blogs (like this one). You can read it more about it in <a href="https://www.netlifycms.org/">Netlify CMS</a> as they have starter projects you can get started with.</li><li><a href="https://firebase.google.com/pricing"><strong>Firebase</strong></a>: In Firebase's free plan (or Spark Plan) they offer many features, including 10GB of hosting. Again, this is great for static websites.</li><li><a href="https://www.heroku.com/"><strong>Heroku</strong></a>: Heroku allows you to host almost any kind of environment. The down side of Heroku's free hosting is that it can be slow, but it still can be very helpful in many cases.</li><li><strong><a href="https://www.alwaysdata.com/en/">alwaysdata</a></strong>: A good hosting solution for a variety of environments, with a lot of features. </li><li><strong><a href="http://surge.sh/">Surge</a></strong>: Surge is another good hosting for static websites. Surge does not really have any limits when it comes to the size of the website, and it's probably the easiest to use. You can deploy any website through their CLI with just one command.</li><li><a href="https://www.000webhost.com/"><strong>000WebHost</strong></a><strong>: </strong>Although I personally am not a big fan of this hosting, but 000WebHost offers an easy to use cPanel free hosting and helpful tools for WordPress hosting in particular.</li><li><strong><a href="https://pages.github.com/">GitHub Pages</a></strong>: Another good static website hosting. The pro of this option is that you can link it directly to your GitHub repository, and with any update to the repository it will update immediately.</li><li><strong><a href="https://hashnode.com/">Hashnode</a></strong>: Hashnode is specific to creating your own blog. You can customize it, track its analytics and much more. If you have your own domain then you can add it, too.</li></ol><hr><h3 id="domain-name">Domain Name</h3><p>Next come domain names. From my experience, the only service that provides a free domain name (without having to pay for hosting, that is) is <strong><a href="https://www.freenom.com/en/freeandpaiddomains.html">Freenom</a>. </strong>Freenom provide free domain names that end with .tk, .cf, .ml, .ga or .gq.</p><hr><h3 id="mail-tools">Mail Tools</h3><p>Whether for a contact form, a newsletter form, or any marketing usage you might have that requires sending email, here's a list to help you achieve that for free:</p><ol><li><strong><a href="https://www.mailgun.com/">Mailgun</a>: </strong>Mailgun provides an email you can use to send email. You can either use Mailgun on your server to send emails, or use the email provided by mailgun and the API keys you get to send emails serverless, but this will require other services.</li><li><strong><a href="https://www.emailjs.com/">EmailJS</a></strong>: EmailJS allows you to send emails from your Javascript without needing a server. You can link EmailJS with your Mailgun account. EmailJS also allows you to manage the email template, email response and other settings as well. It's a great option for a contact form.</li><li><strong><a href="https://www.mailerlite.com/">MailerLite</a>: </strong>MailerLite puts all email marketing together basically. Using MailerLite's free plan you can create forms and popups that you can embed in your website and they take care of the rest. Whether it's a subscription or contact form, you can create the forms, link them with a subscription list, send newsletters and many more options.</li></ol><hr><h3 id="notifications">Notifications</h3><p>Here are some services that offer free notifications for your websites and apps for free:</p><ol><li><a href="https://onesignal.com/pricing">OneSignal</a>: OneSignal allows you to send push notifications on different browsers and mobile apps and more.</li><li><a href="https://pusher.com/beams/pricing">Pusher</a>: Pusher is mainly focused on real time experiences, and part of that is building channels between your server and websites or apps, which allows you to also send notifications.</li></ol><hr><h3 id="seo-and-other-tools">SEO and Other Tools</h3><p>Below are some SEO helpful tools to help make your website a little better:</p><ol><li><strong><a href="https://sharethis.com/">ShareThis</a></strong>: A good tool to let your website visitors share your website easily on almost every social media platform, with a variety of design choices.</li><li><strong><a href="https://disqus.com/">Disqus</a></strong>: Disqus lets you add a comments or reaction section to your website, helping you build connections with your visitors.</li><li><strong><a href="https://crowdin.com/">CrowdIn</a>: </strong>CrowdIn is a tool you can use to manage translations for your projects. You upload a strings file like a .json file, add the languages you want, and then you and your team, or anyone you send the link to can translate your strings easily with their interface and their recommended translations as well.</li><li><strong><a href="https://buffer.com/">Buffer</a></strong>: Buffer allows you to connect your social media accounts together so you can schedule posts, track analytics and more.</li><li><strong><a href="https://www.hotjar.com/">hotjar</a>: </strong>hotjar takes analytics into the next level. Not only can you track the usual traffic of users, but you can also see heatmaps, add surveys, and much more.</li><li><strong><a href="https://www.algolia.com/">Agolia</a></strong>: Agolia allows you to add a search engine to your website without the hassle. </li><li><strong><a href="https://www.rebrandly.com/">Rebrandly</a>: </strong>Provides free URL shortener with analytics, QR Codes and more.</li></ol><hr><h3 id="resources">Resources</h3><p>Here are some websites that you can get design elements, images, or other resources from:</p><ol><li><strong><a href="https://freebiesupply.com/">Freebie Supply</a></strong>: You can find vectors, illustrations, icons, and much more for free.</li><li><strong><a href="https://fonts.google.com/">Google Fonts</a></strong>: Easily use beautiful fonts in your website.</li><li><strong><a href="https://feathericons.com/">Feather Icons</a></strong>: An open source project with very beautiful icons you can use for free.</li><li><strong><a href="https://iconscout.com/">Iconscout</a></strong>: Find free and beautiful icons you can use in your projects.</li><li><strong><a href="https://undraw.co/">Undraw</a></strong>: Free illustrations for any project. You can download the illustrations in PNG or SVG formats and change their colors in website.</li><li><strong><a href="https://unsplash.com/">Unsplash</a>: </strong>Free images you can use in any of your projects. They also have an API you can use to search through images, get random images, and other usages as well.</li><li><strong><a href="https://hatchful.shopify.com/">hatchful</a></strong>: Create a logo and customize it for free.</li></ol><p>For a longer list of design resources, check out <strong><a href="https://blog.shahednasser.com/best-websites-to-find-free-resources-for-frontend-web-developers-and-designers/">my other post</a></strong>.</p><hr><h3 id="conclusion">Conclusion</h3><p>Do you know any other tools or services that are helpful and for free? Please let us know in the comments!</p></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Why I Switched from Atom to VS Code]]></title><description><![CDATA[A few years ago, I discovered Atom and I was amazed by it. Fast forward to now, and I am using Visual Studio Code. What made me switch?]]></description><link>https://blog.shahednasser.com/why-i-switched-from-atom-to-vs-code/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e85</guid><category><![CDATA[My Experience]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 09 Feb 2021 10:56:09 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/f6b4d4620d213392f2a6bbbba17b86b5/photo-1498050108023-c5249f4df085.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/f6b4d4620d213392f2a6bbbba17b86b5/photo-1498050108023-c5249f4df085.jpg" alt="Why I Switched from Atom to VS Code"/><p>A few years ago, I discovered <a href="https://atom.io/">Atom</a>, an open source text and source code editor developed by <a href="https://github.com/">GitHub</a>. I was so amazed by it as it was lightweight and fully customizable. It quickly became my favorite code editor.</p><p>Fast forward to now, and I am using <a href="https://code.visualstudio.com/">Visual Studio Code</a>, a free source code editor developed by <a href="https://www.microsoft.com/en-lb">Microsoft</a>. This might seem like a normal change, however, I remember that while I was using Atom my colleague and I were having a discussion and I strictly stated "I'm not a fan of Microsoft products."</p><p>So what made me switch from Atom to VS Code?</p><hr><h3 id="performance">Performance</h3><p>When I first started using Atom, it was fast and as I mentioned lightweight. However, when you compare it to VS Code, it's load time can be pretty slow. Especially if you're opening somewhat large or long files. Atom can get pretty laggy and the wait becomes annoying.</p><p>It should be noted that both editors are built on <a href="https://www.electronjs.org/">Electron</a>, a framework that helps you built cross-platform desktop app using HTML, Javascript, and CSS. There's a lot of dispute when it comes to Electron's speed, so you'd think that both editors would be inherently slow. However, it seems that VS Code sets an example of how to use Electron without the lag.</p><hr><h3 id="out-of-the-box-features">Out of the Box Features</h3><p>Atom's main charm is that it's customizable. You can add whatever extensions and linters and anything you want. However, especially if you're a beginner in a language and not sure what kind of extensions or linters you might want, it can be a hassle using it. Even if you do find the extensions you need, there's no guarantee that these extensions will do the job well (I'll talk about extensions next). </p><p>Not only does VS Code come ready with support, debuggers and linters for most popular languages, but when you use a new or not so popular language, it recommends the extension you need right away. It saves you time and makes sure you are using what you need in your development.</p><hr><h3 id="extension">Extension</h3><p>Extensions in Atom are tricky. You'll find really good extensions that will be helpful in your development process, but you'll also find extensions that will create more bugs in your editor and makes your life a living hell. This is understandable, as most extensions are made by the open source community, so some extensions might be outdated or get discontinued, or just have a lot of bugs. </p><p>The more extensions you add to Atom, the more you'll face bugs while using it and hassles. And you can't really use Atom without loads of extensions, since using Atom as it is is like walking in the dark. </p><p>As for VS Code, I have been using it for a while now and I have yet to face any problems with its extensions. Every extension that I have added was helpful and very much needed. Nothing affected the quality of the editor.</p><hr><h3 id="debugging">Debugging</h3><p>Debugging in Atom is, again, dependent on what extensions you add. There's nothing built in the editor itself. However, in VS Code, your access to debugging is easier. There's the debugging tab ready for you on the left and it provides what you need based on the environment of the project you're working on. This is another part of the out of the box features in VS Code that Atom lacks in.</p><hr><h3 id="conclusion">Conclusion</h3><p>With time, Atom became an annoyance to me. Every time I needed to add an extension, the entire editor seemed to be crumbling. The load time was slow and the performance got worse. However, VS Code is proving to be a stable editor that can handle your main development need, while still keeping the performance optimal.</p></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Chrome 88 New Feature: Get QR Code For Any URL or Image]]></title><description><![CDATA[In Chrome's new release for Android and Desktop, you can now generate a QR code for any URL with one click.]]></description><link>https://blog.shahednasser.com/chrome-88-new-feature-sharing/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e84</guid><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 06 Feb 2021 14:03:35 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/e8deb38db2cffe45d315a48d5fca9d34/photo-1533228100845-08145b01de14.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/e8deb38db2cffe45d315a48d5fca9d34/photo-1533228100845-08145b01de14.jpg" alt="Chrome 88 New Feature: Get QR Code For Any URL or Image"/><p>In Chrome's new release for Android and Desktop, you can now generate a QR code for any URL or Image with one click. This feature was available before as an experimental feature.</p><hr><h2 id="qr-code-for-url">QR Code for URL</h2><p>On your laptop or Android phone, go to any URL, then click on the URL box and you will see a new QR icon</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/chrome-qr-feature.png" class="kg-image" alt="Chrome 88 New Feature: Get QR Code For Any URL or Image" loading="lazy"/></figure><p>Once you click on the QR icon, You will see the QR code with your URL, and you can choose to download the QR code. It will be downloaded as PNG.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Chrome-QR-Feature-2.png" class="kg-image" alt="Chrome 88 New Feature: Get QR Code For Any URL or Image" loading="lazy"/></figure><p>Then you can just share the QR Code with anyone you want or any social media platform!</p><hr><h2 id="qr-code-for-any-image">QR Code for Any Image</h2><p>To get a QR Code for any image, right click on the image then click "Create QR code for this image"</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/chrome-qr-image.png" class="kg-image" alt="Chrome 88 New Feature: Get QR Code For Any URL or Image" loading="lazy"/></figure><p>Then a pop up will show with the QR Code for the image. You can download it as well.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/chrome-qr-image-2.png" class="kg-image" alt="Chrome 88 New Feature: Get QR Code For Any URL or Image" loading="lazy"/></figure></hr></hr>]]></content:encoded></item><item><title><![CDATA[How I Improved My CSS Skills]]></title><description><![CDATA[CSS for me was what I couldn't do with Bootstrap. So, I decided I'd up my game by looking up challenges online.]]></description><link>https://blog.shahednasser.com/how-i-improved-my-css-skills/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e83</guid><category><![CDATA[CSS]]></category><category><![CDATA[Beginners]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 06 Feb 2021 10:47:03 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/c04f2dcd48f58b78933988cee9d09586/photo-1500933964569-522caa01ca2e.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/c04f2dcd48f58b78933988cee9d09586/photo-1500933964569-522caa01ca2e.jpg" alt="How I Improved My CSS Skills"/><p>Two years ago, I had just gotten employed at my job and we were going through an in between projects and contacts phase. Basically, as a developer, I was bored. </p><p>I didn't want to waste my time, so I decided to improve my CSS skills. Back then CSS for me was what I couldn't do with Bootstrap. It was just simple properties I added here and there. So, I decided I'd up my game by looking up challenges online.</p><p><em>Suggested Read: <a href="https://blog.shahednasser.com/css-variables-and-how-to-use-them/">CSS Variables and How to Use Them</a></em></p><hr><h2 id="codepen-challenges">Codepen Challenges</h2><p>The first place I went to for challenges was <a href="https://codepen.io/challenges">Codepen</a>. Codepen has a new theme of challenges every month, and every week of that month there would be a challenge revolving around the theme.</p><p>The first challenge I did was for for a ghosts challenge (It was October at the time and the theme was Halloween).</p><!--kg-card-begin: html--><p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="NOGYLO" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Nice Ghost"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/NOGYLO"> Nice Ghost</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>Pretty lame to be completely honest. But, with time I moved on to something like this:</p><!--kg-card-begin: html--><p class="codepen" data-height="656" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="xQpBJb" style="height: 656px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Tiger Pattern on Hover List - #CodePenChallenge"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/xQpBJb"> Tiger Pattern on Hover List - #CodePenChallenge</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>And this</p><!--kg-card-begin: html--><p class="codepen" data-height="585" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="EdyrRX" style="height: 585px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Focus Table / Hover Table"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/EdyrRX"> Focus Table / Hover Table</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>Looking back at it, I found these two so hard to do. My skills were so much lacking that designing a table with a hover effect seemed like it was too much.</p><p>Codepen was not enough though, as the challenges were just once a week and I needed to do more. So, I had to look through other challenges online.</p><hr><h2 id="daily-css-images">Daily CSS Images</h2><p><a href="https://gist.github.com/MeFoDy/067daabf9c3ea0e554f045fc067e23b0">Daily CSS Images</a> takes a more fun approach at learning CSS. Basically, everyday you create a certain object or animal, but with CSS. At the time I thought "how would learning how to make a bear be helpful?" but after time I realized that it's not about what you were making, it's about how you make it and what you learn in the process.</p><p>So, I made a bear with CSS.</p><!--kg-card-begin: html--><p class="codepen" data-height="659" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="bmgZdO" style="height: 659px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="CSS Bear Cub - #DailyCSSImages"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/bmgZdO"> CSS Bear Cub - #DailyCSSImages</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>I learned how to use <code class="language-text">rotate</code> and <code class="language-text">transform</code> through this one. I remember I was so confused trying to make the ears in particular. After I was done though, I felt so proud of it.</p><p>Another one I did was a clock. Now this one I needed a tutorial to help me because I didn't know how to make the clock hands move without Javascript. Before doing this, I thought it was impossible to do it with only CSS.</p><!--kg-card-begin: html--><p class="codepen" data-height="415" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="wYpJdP" style="height: 415px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="CSS Alarm Clock - #DailyCSSImages Challenge"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/wYpJdP"> CSS Alarm Clock - #DailyCSSImages Challenge</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>Through making this one it was my first time even hearing about <code class="language-text">transform-origin</code>. I also expanded my knowledge a lot with using transform and animations. This one was a big step up for me.</p><p>I also did an elephant, a beaver, a jellyfish, and a rose. Daily CSS Images Challenge helped me understand more about animations and transforms and perspective in CSS. </p><p>Daily CSS Images Challenge also helped me step up my CodePen Challenges game!</p><!--kg-card-begin: html--><p class="codepen" data-height="769" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="VVPYLK" style="height: 769px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="CodePen Challenge - Panda"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/VVPYLK"> CodePen Challenge - Panda</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>Although these challenges helped, I needed to move on to something more realistic. A challenge where I would make something that I would actually make in a real project.</p><hr><h2 id="100-days-css-challenge">100 Days CSS Challenge</h2><p><a href="https://100dayscss.com/">100 Days CSS Challenge</a> was my favorite challenge to be a part of. First off, their website featured the works of developers who participated on CodePen, so it was a nice boost for me. Also, their challenges looked so beautiful to me, and in a lot of cases, something I'd love to do on a next project of mine.</p><p>The first challenge I did was this:</p><!--kg-card-begin: html--><p class="codepen" data-height="542" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="wYJxvx" style="height: 542px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="#100daysCSSChallenge"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/wYJxvx"> #100daysCSSChallenge</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>A simple grid of images that shows a heart on hover. Yes, it is simple, but again because I lacked in my skills it was helpful.</p><p>I also did this Search bar:</p><!--kg-card-begin: html--><p class="codepen" data-height="560" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="XxOPOQ" style="height: 560px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Search Bar - 100 Days CSS Challenge"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/XxOPOQ"> Search Bar - 100 Days CSS Challenge</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>And this counter:</p><!--kg-card-begin: html--><p class="codepen" data-height="530" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="PygOzB" style="height: 530px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Counter - 100 Days CSS Challenge"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/PygOzB"> Counter - 100 Days CSS Challenge</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>Again, all simple concepts, but it was still really helpful. I learned how to make prettier designs. CSS isn't just about knowing how to do something or memorizing the properties, it's also about utilizing what you know to make a visually pleasing design.</p><p>These challenges also had Javascript in them so it was helpful to practice Javascript as well.</p><hr><h2 id="codevember">Codevember</h2><p>Another challenge I took on as well was <a href="http://codevember.xyz/">Codevember</a>. Codevember ran from 2016 till 2019, and it would show a list of challenges for every day in November.</p><p>Codevember's challenges were simple. Each day would have a keyword and you have to create something that relates to it. This helps shift your perspective from just coding with CSS to using your imagination to find an idea, then think how would I bring this idea to life with CSS.</p><p>So, at first when the concept was Infinity, I took a pretty simple approach to it:</p><!--kg-card-begin: html--><p class="codepen" data-height="486" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="eQZGbX" style="height: 486px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="#codevember - 01 - infinity"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/eQZGbX"> #codevember - 01 - infinity</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>But when the concept was Web, I made a spider sitting on a web (with the help of SVG):</p><!--kg-card-begin: html--><p class="codepen" data-height="477" data-theme-id="dark" data-default-tab="result" data-user="shahednasser" data-slug-hash="pQNRKO" style="height: 477px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="#codevember - 03 - Web"> <span>See the Pen <a href="https://codepen.io/shahednasser/pen/pQNRKO"> #codevember - 03 - Web</a> by Shahed Nasser (<a href="https://codepen.io/shahednasser">@shahednasser</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"/><!--kg-card-end: html--><p>It helped me think more creatively and then try to find a way to do it with CSS, while maintaining what I learned from 100 Days CSS Challenge to make it visually pleasing.</p><hr><h2 id="conclusion">Conclusion</h2><p>Everyone knows that to improve your skill in any programming language, you need to practice. Even if it seems hard in the beginning, with time you will improve and you will learn new concepts and ways of thinking as well. Whether it's CSS or any other programming language, look online for motivating challenges to keep you going and practicing to become a better developer.</p></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[5 UX Issues Apple Needs To Fix In The Messages App]]></title><description><![CDATA[The user experience in the Messages App needs more attention and improvement, especially when certain features are available in easier ways in other apps. ]]></description><link>https://blog.shahednasser.com/5-ux-issues-apple-needs-to-fix-in-the-messages/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e82</guid><category><![CDATA[My Experience]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Fri, 05 Feb 2021 07:37:02 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/0edac04210c458a826788d8dd167e804/photo-1552947602-4640901e9c67.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/0edac04210c458a826788d8dd167e804/photo-1552947602-4640901e9c67.jpg" alt="5 UX Issues Apple Needs To Fix In The Messages App"/><p>I use iMessage every day, and there are functionalities I always use that end up annoying me. The user experience in the Messages App needs more attention and improvement, especially when certain features are available in easier ways in other apps. </p><p>I will point out 5 UX issues I have faced in the Messages App and their impact or how they can be fixed.</p><hr><h2 id="better-way-to-reply-to-specific-message">Better Way to Reply to Specific Message</h2><p>Every app that has messaging in them (except Twitter for some reason) have the reply feature. If you've used Instagram or Whatsapp, you'll know that you can easily reply to a message just by swiping it.</p><p>In Messages, you have to either double tap or long press on the message you want to reply to, then choose "Reply" and then you can reply to the message. But why? It's so annoying when you use this a lot as it takes a lot of presses here and there to do what can be done in a very simple manner.</p><h3 id="the-ux-issue">The UX Issue</h3><p>Users need 2 or 3 clicks to be able to use the feature. When you can save the user even one click, then you shouldn't overlook it.</p><hr><h2 id="voice-messages-without-the-hassle">Voice Messages Without The Hassle</h2><p>Voice messages in Messages (that sounds weird) is plain annoying to be completely honest. If you had to leave the app for some reason or wanted to listen again to just one small part a few seconds earlier in the message, you have to re-listen to the entire thing all over again to get to where you were. And if you are inside the app, you need to leave it and then open it again to be able to replay from the beginning. </p><p>This problem, as far as I am aware, is not found in any other messaging app. I'm not sure what's next on their list for this app but I hope fixing this is one of their priorities.</p><h3 id="the-ux-issue-s-">The UX issue(s)</h3><p>The users have to figure out on their own how to get something done. It should be easy and accessible for the user to do something so trivial. The more you can make things easier for the user, the better.</p><hr><h2 id="sending-a-photo-after-typing">Sending A Photo After Typing</h2><p>This is probably a bug rather than a UX issue, but I'm placing it here anyway. When you want to send a photo, you just click on the Photos App then choose the photo you want to send. </p><p>However, if you type out the message then you want to pick the photo you want to send, it's not possible to get to the Photos app again. The arrow button next to the text box does not work, so you have to remove your message to be able to add the Photo, then paste or type out your message again.</p><h3 id="the-ux-issue-1">The UX Issue</h3><p>As I stated, this is probably a bug. However, for the sake of this post, the issue here is that we're providing hassles for the user to get to what they need to do. Users can be forgetful and they need a way to go back when they mess up or forget.</p><hr><h2 id="force-scrolling-when-a-message-is-received">Force Scrolling When A Message Is Received</h2><p>If you are scrolling back in a chat to go back to a certain previous message, and the person in the chat sends a new message, the app scrolls back to the new message. This is so simple yet annoying as I have had to clearly tell the other person "STOP SENDING MESSAGES" to be able to go back to a previous message.</p><p>I'm not sure why scrolling to the new message is necessary. A better UX would be showing you an arrow that when you press it takes you to the new message, like Whatsapp and Instagram.</p><h3 id="the-ux-issue-2">The UX Issue</h3><p>This issue implies that the team working on the Messages app probably doesn't understand users well, to be honest. Forcing users to go from one place to another is just plain annoying.</p><hr><h2 id="undo-message">Undo Message</h2><p>This one is not actually available in the app, which is the problem itself. We all tend to make mistakes, like sending a message to the wrong person (be careful with those screenshots) or sending the wrong photo. An undo or delete from end to end is very needed to make the app better. </p><h3 id="the-ux-issue-3">The UX Issue</h3><p>Again, it's very important as part of your UX to actually understand users. Users make tons of mistakes on the go, and we should make it easier for them to correct or revert their mistakes. </p><hr><h2 id="conclusion">Conclusion</h2><p>To realize the importance of fixing UX issues and improving the UX in your apps/websites, just look back at how I kept comparing Messages to other apps like Whatsapp or Instagram. When users find a better alternative for them that understands them and their patterns, they will just ditch your app for the alternative. That is why we need to make sure to understand our users and provide the best solutions for them.</p><p>Are there other issues you found as well that are not mentioned here? Let me know!</p></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Google In Dark Mode]]></title><description><![CDATA[If you're anything like me, then you must love Dark Mode on anything. It is cooler and classier, but also easier for the eyes. So, what if Google was in Dark Mode?]]></description><link>https://blog.shahednasser.com/google-in-dark-mode/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e81</guid><category><![CDATA[CSS]]></category><category><![CDATA[Design]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 04 Feb 2021 07:44:01 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/ac4d8a92057297fd689566be0039ed6a/photo-1573804633927-bfcbcd909acd.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/ac4d8a92057297fd689566be0039ed6a/photo-1573804633927-bfcbcd909acd.jpg" alt="Google In Dark Mode"/><p>If you're anything like me, then you must love Dark Mode on anything. It is cooler and classier, but also easier for the eyes. It is now getting adapted more in most sites and apps, however, not all of them are going with the trend yet.</p><p>The website that we all use the most almost every day is one of them. Google, everyone's favorite search engine, does not support dark mode. So, for the fun of it I thought I'd try and imagine how Google's Dark Mode would look like.</p><p>I will be using Material's <a href="https://material.io/design/color/dark-theme.html#properties">Dark theme</a> for the color palette for the dark mode.</p><hr><p>You already know this but just for the sake of comparison, this is how Google looks like by default:</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/google-before.png" class="kg-image" alt="Google In Dark Mode" loading="lazy"/></figure><p>The first obvious step is to change the background color of the <code class="language-text">body</code> to a dark color, and change the color of the text in the <code class="language-text">body</code> to a light color. Based on Material's Dark Theme, the dark color that we will be using for the body is <code class="language-text">#121212</code> and the light color for the text is <code class="language-text">#fff</code>. </p><p>So, this is the CSS I'll be adding:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">body</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> #121212<span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>And this is the result:</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/google-first-step.png" class="kg-image" alt="Google In Dark Mode" loading="lazy"/></figure><p>More work needs to be done. We have sections in the body that explicitly have their background color set to white. </p><p>After inspecting the elements in Chrome's Devtools, I found that the elements that have white background color are: <code class="language-text">#hdtb</code> and <code class="language-text">.yg51vc</code> for the navigation bar, <code class="language-text">#appbar</code> for the results bar (the one that shows the number of results found), <code class="language-text">.sfbg</code> for the background of the header, and <code class="language-text">.RNNXgb</code> for the background color of the input. I also noticed that <code class="language-text">#hdtb</code> has a border bottom and the color of it is set to <code class="language-text">#ebebeb</code> which is a light color, so it needs to be changed as well.</p><p>I know what you are thinking, these classes and IDs must be randomly generated. That's what I thought too, however, after testing it on a few tries I found that they are not random. They're always the same.</p><p>So the next rules I added were as follows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">#hdtb, .yg51vc, #appbar, .sfbg, .RNNXgb</span> <span class="token punctuation">{</span> <span class="token property">background</span><span class="token punctuation">:</span> #121212<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.RNNXgb</span> <span class="token punctuation">{</span> <span class="token property">background</span><span class="token punctuation">:</span> #2b2b2b <span class="token important">!important</span><span class="token punctuation">;</span> <span class="token comment">/** Give it a different color than the background to stand out **/</span> <span class="token punctuation">}</span> <span class="token selector">.gLFyf</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span> <span class="token comment">/** The input for the search field **/</span> <span class="token punctuation">}</span> <span class="token selector">#hdtb</span> <span class="token punctuation">{</span> <span class="token property">border-bottom-color</span><span class="token punctuation">:</span> #1F1B24<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>And this was the result:</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/google-second-step.png" class="kg-image" alt="Google In Dark Mode" loading="lazy"/></figure><p>So, now the background is dark, but there's a lot more work to do. </p><p>Almost all of the text in the page was not affected by changing the <code class="language-text">color</code> for the <code class="language-text">body</code> element. So, we need to inspect the elements and see how to change it.</p><p>I started with the navigation bar. After inspecting it, the elements <code class="language-text">.hdtb-mitem a</code>, <code class="language-text">.hdtb-mitem .GOE98c</code> and <code class="language-text">.GshZze</code> have the color set to <code class="language-text">#5f6368</code>. So, I added the following rules:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.hdtb-mitem .GOE98c, .hdtb-mitem a, .GshZze</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> #FFFFFF <span class="token important">!important</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>And this was the result:</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/google-third-step.png" class="kg-image" alt="Google In Dark Mode" loading="lazy"/></figure><p>Next, the results bar. The class that had the color set to it was <code class="language-text">.LHJvCe</code>. So I added the following rules:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.LHJvCe</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> #FFFFFF<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>And this was the result:</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/google-fourth-step.png" class="kg-image" alt="Google In Dark Mode" loading="lazy"/></figure><p>Next, I moved on to the text and links in the results. Starting with the text and after inspecting the elements, the elements <code class="language-text">.IsZvec</code> and <code class="language-text">.aCOpRe em</code> need to be changed. I noticed that <code class="language-text">.aCOpRe em</code> is used to point out the text that's included in the search query, so I decided to give it a different color.</p><p>I added the following rules:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.IsZvec</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> #adadad<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.aCOpRe em</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> #e4e4e4<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>As for the citation, or the links breadcrumb above the result, the element that needed to change was <code class="language-text">cite</code>. I added the following rules:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">cite, cite a:link, cite a:visited</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> #9c9c9c<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>And this was the result:</p><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/google-fifth-step.png" class="kg-image" alt="Google In Dark Mode" loading="lazy"/></figure><p>Now for the links of the results, Google just sets the color rule on all <code class="language-text">a</code> elements. For the "Translate this page" link it sets the rule on <code class="language-text">a.fl:link</code>. Pretty simple. So I added the following rule to change the color: </p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">a, a.fl:link</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> #BB86FC<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">a:visited</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> #9326ca<span class="token punctuation">;</span> <span class="token comment">/** color for the visited links **/</span> <span class="token punctuation">}</span></code></pre></div><p>And finally the result was:</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/google-last-step.png" class="kg-image" alt="Google In Dark Mode" loading="lazy"/></figure><p>And we're done! Obviously, this is just for the main results page of the website, but it looks nice.</p><p>For comparison, here's the difference between the light and dark modes:</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/google-before.png" width="1844" height="820" loading="lazy" alt="Google In Dark Mode"/></div><div class="kg-gallery-image"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/google-last-step.png" width="1838" height="823" loading="lazy" alt="Google In Dark Mode"/></div></div></div></figure><hr><h2 id="conclusion">Conclusion</h2><p>Which version did you like of Google more? And which websites or apps do you wish they had dark mode? Let me know!</p></hr></hr>]]></content:encoded></item><item><title><![CDATA[My Horrible Experience With Freelancer.com]]></title><description><![CDATA[I had such high expectations going into Freelancers.com but was faced with problems that made me realize how it doesn't prioritize freelancers.]]></description><link>https://blog.shahednasser.com/my-horrible-experience-with-freelancer-com/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e80</guid><category><![CDATA[My Experience]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 02 Feb 2021 11:37:03 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/d60b37d2cae8e4fab7b6a3cf20535bef/photo-1487073240288-854ac7f1bb3c.jpg" medium="image"/><content:encoded><![CDATA[<h3 id="update">UPDATE</h3><img src="https://blog.shahednasser.com/static/d60b37d2cae8e4fab7b6a3cf20535bef/photo-1487073240288-854ac7f1bb3c.jpg" alt="My Horrible Experience With Freelancer.com"/><p>2 days after posting this, Freelancer's support team has reached out and worked out the balance issue. Hopefully, in the future situations similar to mine will be handled better and Freelancer becomes about freelancers again.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/asset.png" class="kg-image" alt="My Horrible Experience With Freelancer.com" loading="lazy"/></figure><hr><p>I have been working as a freelance web developer since 2017. I have worked on many projects including financial auditing management, reservation and booking systems, e-commerce projects, and many more. All of these projects I have worked on locally with people from the same country.</p><p>However, I've always wanted to try Freelancer.com. It seemed like it would provide good opportunities, and frankly easier ways to make money as a freelancer. So, in December, I decided to expand my freelancing journey there. </p><hr><p>If you don't know what Freelancer is, it's a platform that provides a connection between freelancers and job posters from all over the world. It's mostly used by developers or designers, but it can be used for any sector and industry. If you have a job that you want done, you just post a project with the descriptions and budget. If you're a freelancer, you can search through projects and bid on the ones you like, explaining why you'd be perfect for the job and what your fees are.</p><p>I had such high expectations going in. Not only does Freelancer have so many users, but if you check their profile summaries you'll see that these users might have done over hundreds of projects and made good amount of money through Freelancer. If it happened to others, why can't it happen to me?</p><hr><p>After creating my account, Freelancer encouraged me to verify my identity. They first ask you for a pic of your ID or Passport or any identification you have. Next, you will be asked to write a code provided by Freelancer on a paper and take a picture with it. I did both of those things and passed their verification process. </p><p>However, I was then met by my first problem on Freelancer. The last step you have to do to verify your identity is to provide a proof of address. If you have done this on any website before, you are usually asked to provide any bill that proves your address. For Freelancer, it's more strict than this. You are asked to provide a utility bill, a contract or something official that not only has your full name, address, and phone number on, but also the company or other party's details as well.</p><p>For some people this is easy to do, however, if you're like me, a person that comes from a culture where living with your family is normal and having the bills in someone else's name, even governmental forms, it's not possible.</p><p>So, since Freelancer made it seem like identifying your identity is just an optional process that just gives you a boost, I decided to not finish the process. I can still bid and be assigned to projects, so it's not going to stop me.</p><hr><p>I started then applying for projects, and that's when I faced more problems. </p><p>If you're not a Freelancer Plus member, you only get 6 bids when you create your account. After that, you get new bids only after 5 days. You get at most 6 bids, which means even if you leave your account for a while, it will not cross the 6 bids limit. </p><p>As a beginner, getting a project is not easy at all. Job posters will mostly look at the reviews you have or number of projects you worked. And it doesn't help that those with higher reviews or higher plans on Freelancer show up higher in the bids of a project than beginners who don't have any reviews. So, 6 bids a month will not be of any help to get your reviews higher and getting more jobs.</p><p>This is another issue that Freelancer has. It does not give a chance to new comers. Its system ensures that only those with high reviews or paid plans get a better chance at getting hired. Even if you do have a paid plan you still will not get as much of a chance as anyone with a 5 stars review.</p><p>So, I decided to start a free trial on the plus membership. You get a 100 bid a month, approximately 3 bids a day. This was helpful as I could bid on more projects and increase my chance of getting my first project on Freelancer.</p><p>Even when you bid on many projects, it's still not easy to get a project on Freelancer. Again, no review, no one will see you. </p><p>Another problem you'll notice when using Freelancer is that there are certain tags for projects that will get over 50 bids in a minute. For example, check any Wordpress job. You'll find that after 2 minutes or even less of it getting posted, it already has so many bids, and most of these bids are by companies and not individuals. You'll realize soon that companies who can take on different projects, and not individual freelancers, are the ones who can actually make money and get projects on Freelancer.</p><hr><p>After bidding for a few days on so many projects, I finally got a project to develop a portfolio website for a company. Then, I got another small project just to add a google analytics link to a website and fix some email issues the poster had.</p><p>When taking jobs on Freelancer, your balance will immediately drop even before you start working on the project or getting paid. That is because Freelancer takes their share the minute you are assigned the project, regardless of how the project actually goes.</p><p>I finished the small project and started working on the portfolio website. Then, I found out something that was the main problem of working on Freelancer.</p><hr><p>Freelancer has a few ways you can withdraw your money: Wire Transfer, Express Withdrawal, Paypal, and Skrill. Most of these methods are not available in all countries, which means Wire Transfer is the only method that's available for your country regardless of where you are.</p><p>However, Wire Transfer (and all payment methods) requires that you verify your identity. Then shouldn't this make verifying your identity mandatory, and not optional? Freelancer could point that out when it asks you to verify your identity, that you will need this to verify your identity. Instead, Freelancer just points out that it's good for the job poster and your profile to verify your identity.</p><p>I contacted their support, and when explaining my inability to provide a proof of address since it's asking for something that is not available for me, I was told it was because of Freelancer's strict policy and because they want to maintain "the security of the website."</p><p>Ok, so that's understandable in a sense. However, I did a project with a job poster, I finished the project, I received a 5-star review, and the job poster paid for the job. Shouldn't this provide as a source of guarantee that I'm doing my job properly and that I'm not misusing Freelancer or breaking its security? If not, then shouldn't I at least get paid for the work I've done?</p><p>I followed up with an email asking how can I withdraw my money, and I was simply told that it's not possible for me to withdraw my money in my location.<br>Was this information not available for Freelancer on my registration? If you do not provide a withdrawal method to my country, then shouldn't you remove my country from the list of countries on registration, or at least in your FAQs and help sections?</br></p><p>So, I decided to end my journey on Freelancer, but it wasn't that simple. After messaging the person from the first job posting that I'm unable to finish the project due to the inability of withdrawing the money, they labeled the project as incomplete. However, my balance on Freelancer remained in the negative value. They still want me to deposit their fee for the project that was not completed, even though I didn't technically get paid for the project that I did complete.</p><hr><h3 id="conclusion">Conclusion</h3><p>You may think this story does not apply to you because you wouldn't face similar problems regarding identity verification or money withdrawal, however, one thing is evident: Freelancer does not prioritize freelancers. You should know this when before you even get paid, they take their share of their money. They make sure that those who use their plans get their jobs. They gloss over some details and their customer support was not helpful in fixing the issues I was having. If you are not a Freelancer user, then honestly don't bother being a part of it.</p></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Best Free Platforms To Learn Programming in 2021]]></title><description><![CDATA[In this article, I will list websites and apps that will help you start or continue your journey in the world of programming.]]></description><link>https://blog.shahednasser.com/best-platforms-to-learn-programming-in-2021/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e77</guid><category><![CDATA[Beginners]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 28 Jan 2021 14:34:58 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/e9818cc00005b71bd82f0d24b45948ab/photo-1550645612-83f5d594b671.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/e9818cc00005b71bd82f0d24b45948ab/photo-1550645612-83f5d594b671.jpg" alt="Best Free Platforms To Learn Programming in 2021"/><p>As a new year comes along, it's the perfect time to set new goals and learn new things. One of the most important things you should learn in our time and age is programming.</p><p>Whether you already are a programmer or a beginner who wants to get started with it, I will list websites and apps that will help you start or continue your journey in the world of programming.</p><!--kg-card-begin: html--><div class="suggested-read"><h4>Suggested Read</h4><p>For Beginners 12+, check out Juni's article <a href="https://junilearning.com/blog/coding-projects/how-to-make-your-own-website?referrer=blogshahednasser" target="_blank">How to Code Your Own Website (for Beginners 12+) | Beginner Web Development</a>!</p></div><!--kg-card-end: html--><h2 id="codecademy"><a href="https://www.codecademy.com/">Codecademy</a></h2><p><a href="https://www.codecademy.com/" rel="noopener">Codecademy</a> is a great platform for learning. It is the platform that helped me kick start my web development path and the platform I always check for new tutorials and learning paths.</p><p>Codecademy is a learn-by-practice platform. It helps you understand the core concept of what you are learning, but also shows you how it works by letting you do it. With their simple explanation and integrated editors and previews, you can learn and practice what you’ve learned all in one place.</p><p>Codecademy has learning paths (or tutorials) for web development frameworks like React, Data Science, Mobile Development, and more. It used to be only a website but now they have a mobile app so that you can learn on the go.</p><h2 id="edabit"><a href="https://edabit.com/?ref=shahednasser1">Edabit</a></h2><p><a href="https://edabit.com/?ref=shahednasser1">Edabit</a> is a website where you can learn a programming language through challenges. You can find languages for many programming languages like C++, C#, Swift, Ruby, Javascript, and more.</p><p>When solving challenges, you can also see resources that will help you understand how you can solve the challenge. You can also discuss with other users the best way to solve challenges. It’s very helpful in not only learning a programming language but also in learning problem-solving through the challenges.</p><h2 id="udemy"><a href="https://www.udemy.com/">Udemy</a></h2><p><a href="https://www.udemy.com/">Udemy</a> is very helpful for those who like to learn through courses, with instructors and resources available. Udemy is a platform to learn anything, and one of those things is programming. </p><p>Although most of the courses are not free on Udemy, you can still find free courses that are very helpful. For example, I took a course about Web Design that was really helpful. You can check <a href="https://shahednasserblog.tk/web-design-tips-for-web-developers/">my summary</a> about it as well.</p><!--kg-card-begin: html--><div class="suggested-read"><h4>Suggested Read</h4><p>Take Free Coding and Programming Courses on <a href="https://www.futurelearn.com/subjects/it-and-computer-science-courses/coding-programming" target="_blank">FutureLearn</a>!</p></div><!--kg-card-end: html--><h2 id="w3schools"><a href="https://www.w3schools.com/">W3Schools</a></h2><p>If you ask any web developer about <a href="https://www.w3schools.com/" rel="noopener">W3Schools</a>, they all will say that they have at least visited it 10 times throughout their journey in learning web development. W3Schools is a website that has tutorials on the most important programming languages and concepts you’ll need in web development.</p><p>The explanation is simple and divided in a way that makes it easy for any programmer to learn from it. Even those who already are skilled programmers still refer to it when they need to remember a function.</p><h2 id="codepen"><a href="https://codepen.io/">Codepen</a></h2><p>Although Codepen is not labeled as a learning platform, it was very helpful for me while learning, practicing, and expanding my skills in CSS. Whether it was through seeing people’s ideas and taking inspiration from them, or through the weekly and daily challenges they provide on Codepen, I was able to practice my CSS and become much better at it.</p><p>Codepen is also good for practicing Javascript, SCSS, and much more. It does not provide you with tutorials, but it helps you practice what you know and try new ideas as well.</p><h2 id="sololearn"><a href="https://www.sololearn.com/">SoloLearn</a></h2><p>SoloLearn is another platform that provides simple, learn-by-practice tutorials on different programming languages. Although from personal experience I wouldn't say it's on the same level as Codecademy, it is still helpful for beginner programmers who are still not familiar with a lot of concepts in programming. </p><p>Their tutorials are light and fun, not too complicated. I would consider it a great platform to start getting into programming and maybe deciding where you want to go from there. Also, once you finish learning a programming language you will be provided with a certificate from SoloLearn!</p><h2 id="codingame"><a href="https://www.codingame.com/">CodinGame</a></h2><p><a href="https://www.codingame.com/" rel="noopener">CodinGame</a> is another platform that helps you learn programming languages through solving challenges. However, CodinGame is unique as its challenges are all related to games. Instead of solving the same old challenges that you will find on all challenge-learning based platforms, you get to solve challenges that are parts of games.</p><p>You can choose from many languages to solve any challenge, and you will be able to use their editor right on the website, with a simulation showing you your results in the game. You can also participate in contests against other users. The entire experience feels like a fun game!</p><h2 id="google-developers-training"><a href="https://developers.google.com/training">Google Developers Training</a></h2><p>On <a href="https://developers.google.com/training">Google Developers Training</a>, you can learn about Web and Android Development. You can also learn about Firebase, Machine Learning, and more. </p><p>The training can be videos, Code Lab and quizzes. They have different paths for Android Development, for beginner and advanced programmers. This helps you understand Android Development more clearly as a beginner, then transition to the advanced programmer training as you progress your skills. You can learn in Kotlin or in Java.</p><h2 id="medium-and-developers-blogs"><a href="https://medium.com/">Medium</a> and Developers' Blogs</h2><p>Blogs are a great way to learn concepts about programming in general. You can find specific tutorials or solutions to the problems you are facing.</p><p><a href="https://medium.com/">Medium</a> is a blogging platform where you can find tutorials and articles about many programming languages or problem solutions. You can also find on google other blogs that will help you throughout your journey.</p><h2 id="github"><a href="https://github.com/">GitHub</a></h2><p>Although <a href="https://github.com/" rel="noopener">GitHub</a> is not directed towards learning programming, it is very important for any programmer to start experimenting with GitHub.</p><p>By contributing to other open-source projects and helping the community, you can expand your knowledge in different areas while helping open source projects.</p><p>If you’re a beginner and you’re not sure where to start, you can check out a list of beginner-friendly projects <a href="https://github.com/MunGell/awesome-for-beginners" rel="noopener">here</a>. I personally have a repository and open source project <a href="https://github.com/sButtons/sbuttons" rel="noopener">sButtons</a>, that welcomes everyone including beginners, that you can also start contributing to.</p><h2 id="conclusion">Conclusion</h2><p>The list above is among many platforms that will help you learn programming in 2021. Do you know other platforms that would also be helpful for learning new languages? Let me know below!</p>]]></content:encoded></item><item><title><![CDATA[If You're A Developer, You Need to Know This]]></title><description><![CDATA[There are many mistakes you can make as a developer throughout your career. Some you will not realize until later and you will wish you already knew them.]]></description><link>https://blog.shahednasser.com/if-youre-a-developer-you-need-to-know-this/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e7f</guid><category><![CDATA[Tips]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 26 Dec 2020 10:58:34 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/a4623023ba5ad1fd67eb8f8abafcaddb/photo-1573166801077-d98391a43199.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/a4623023ba5ad1fd67eb8f8abafcaddb/photo-1573166801077-d98391a43199.jpg" alt="If You're A Developer, You Need to Know This"/><p>There are many mistakes you can make as a developer throughout your career. Some you will not realize until later and you will wish you already knew them. I'm not talking about programming languages or frameworks or anything technical, this is more related to your work ethic and how you handle yourself throughout your years of experience.</p><hr><h2 id="know-your-worth">Know Your Worth</h2><p>I put this at the top of the list because this is, in my opinion, the most important thing you need to learn. This is especially important if you're coming across a new opportunity. Sometimes the opportunity is less than what you deserve, but you still consider it thinking it's the only option. Other times it could be a great opportunity, but you think you don't have what it takes to do it and you back out from trying. </p><p>It's not just in new opportunities. Some people get stuck at a job that isn't help them advance or learn anything new just because they think they won't find a better opportunity out there.</p><p>You need to believe in yourself and know your worth. It's not about how many technical stuff you know. Yes, that part is obviously important as well, but you can always learn new languages or frameworks or concepts. If you find yourself lacking in this part and that's standing in your way, then start advancing and learning so that you can keep valuing yourself and aiming higher.</p><hr><h2 id="value-your-years-of-experience">Value Your Years of Experience</h2><p>This doesn't just apply to those that already have more than 2 years of experience, this also applies to anyone just starting out now. Value the time and effort that you have put or are putting into a job or a project, regardless of how big or small it is. Every day through working on it, you gain and learn something new, which makes future experiences easier. </p><p>This mostly happens with freelancers. A lot of freelancers are unsure of how much they should price their work, scared that it will be too high. Same thing for full time developers that are scared to ask for a raise or leave a job that's underpaying them. Remember how much time and effort you've put into getting to where you are now. When you work with or for someone, you are bringing your knowledge and experiences with you, and that's worth a lot. So, don't be scared of asking for exactly your worth. You are working hard to become better and deliver high quality services.</p><hr><h2 id="advance-your-skills-in-a-specific-path">Advance Your Skills in A Specific Path</h2><p>When you become a developer, you may get overwhelmed by all the things you can learn and do. You might dip your feet a little in Web Development, a little in App Development, Game Development, etc... It's nice and important to learn a little of everything of course, but make sure that you pick one path that you like the best and focus on expanding in it. Technology is always advancing and growing and you need to be at the top of it. If you don't choose one path, you might get lost in the chaos and end up an expert in nothing. Focus your attention and energy to one of them and become the expert in it.</p><hr><h2 id="you-don-t-need-to-know-everything">You Don't Need To Know Everything</h2><p>This is a follow up to the previous one. You might get intimidated by others who know more than you or think that you need to know everything to be good at this job. You don't. You need to remember first and foremost that no one knows everything, and there will always be someone who knows more than you, just like you'll always know more than someone else. Keep focusing on the path you have chosen and moving forward in it. Let other people's knowledge inspire you, but not intimidate you or distract you from your own path.</p><hr><h2 id="everyone-uses-google">Everyone Uses Google</h2><p>This is more directed towards beginners or those that are just learning about development. If you run into a problem or forget something, don't be embarrassed or think it makes you less to use Google. Everyone, including those with many years of experience, can forget sometimes and have to google a syntax or a function or an error they face. There's nothing wrong with it and in fact you need to learn how to use Google to your side. Wracking your brain and wasting time trying to figure it out yourself is not always desired, especially when someone out there have already went through it and you can learn from it just by searching it.</p><hr><h2 id="don-t-let-what-looks-complicated-discourage-you">Don't Let What Looks Complicated Discourage You</h2><p>I think we all have went through this or some are going through it now. You see something that looks complicated, maybe above your level, and you think there's no way that I'll be able to do this. Whatever it is that looks complicated or hard to you, know that if you give it time and you work hard on yourself, with time you will realize that it isn't. </p><hr><h2 id="don-t-look-around-keep-looking-forward">Don't Look Around, Keep Looking Forward</h2><p>This one took me a while to understand and apply. As a woman in this career, I have faced some problems finding a job and dealing with clients, who undermined me just because of the fact that I'm a woman. It can get discouraging and make you want to give up, but the best counter attack is to keep working hard on yourself. If you feel like you are judged in any way in your work place or when finding a job, don't let that put you down. Instead, work hard on improving your skills, whether they are soft skills or technical skills, because with time you will become an asset that they can't look down on.</p><p>You should also remember that at the end of the day it doesn't matter how others look at you, what matters is how you see yourself. Work hard to be confident in your own identity and not let anyone put you down by their judgments.</p><hr><h2 id="conclusion">Conclusion</h2><p>These are some things I've learned through my journey as a developer. If you have other lessons that you think others should know as well, please let us know in the comments!</p></hr></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Here's Why You Should Be Using Overrides in Chrome Devtools]]></title><description><![CDATA[Chrome Devtools are packed with many tools that can help your testing, debugging, and development in general easier and faster. One of them is Overrides.]]></description><link>https://blog.shahednasser.com/overrides-in-chromes-devtools/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e7e</guid><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 21 Dec 2020 08:44:04 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/a53635c5030d2517d6a302c5947bea87/photo-1499951360447-b19be8fe80f5--1-.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/a53635c5030d2517d6a302c5947bea87/photo-1499951360447-b19be8fe80f5--1-.jpg" alt="Here's Why You Should Be Using Overrides in Chrome Devtools"/><p>Chrome Devtools are packed with many tools that can help your testing, debugging, and development in general easier and faster. There are many features that developers are not familiar with or don't use often. One of those features is Overrides.</p><hr><h2 id="what-is-overrides">What is Overrides</h2><p>Overrides is a feature in devtools that helps you override any asset in a website and make changes to it, like Javascript or CSS files. You can override files that a website uses and see your changes in action on the website right away.</p><hr><h2 id="why-use-overrides">Why Use Overrides</h2><p>When debugging websites, so many people make edits in the Sources panel in the Page panel to quickly test something. This can be helpful in some cases, however, those changes that you make are not permanent. Once you reload the page, the changes will be gone. So, if you are testing or debugging something throughout different pages or on load of a certain page, this method will not work.</p><p>Overrides are persistent as long as the devtools are open. When you override a file and make changes to it, the changes will persist even after you reload the page or switch to a different page.</p><p>Overrides can be extremely helpful when you are debugging a bug on your website or chrome extension that's only happening in production. Other methods to do that can be a hassle or ineffecient.</p><hr><h2 id="how-to-use-overrides">How to Use Overrides</h2><p>To use Overrides, open the Devtools either from the settings or using the keyboard shortcut <code class="language-text">CTRL+SHIFT+I</code>. </p><p>Then, Click on the <strong>Sources</strong> tab. You'll see at the top of the left menu 3 tabs: <strong>Page</strong>, <strong>Filesystem</strong>, and <strong>Overrides</strong>.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/devtools.jpg" class="kg-image" alt="Here's Why You Should Be Using Overrides in Chrome Devtools" loading="lazy"/></figure><p>Click on <strong>Overrides</strong>. Below it you will see "<strong>Select folder for overrides." </strong>Click on it and choose a folder. This folder will store all the overrides you make.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/devtools-2.jpg" class="kg-image" alt="Here's Why You Should Be Using Overrides in Chrome Devtools" loading="lazy"/></figure><p>Once you select a folder, a prompt will show up at the top of the page. Click <strong>Allow</strong>.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/devtools-3.jpg" class="kg-image" alt="Here's Why You Should Be Using Overrides in Chrome Devtools" loading="lazy"/></figure><p>When you do, you are ready to use overrides on this website. You can go back to the devtools <strong>Sources </strong>tab, then click on <strong>Page. </strong>Choose a file like a Javascript or CSS files, right click it and choose "<strong>Save for overrides." </strong>The file you choose will now appear in the Overrides tab.</p><p>Now, any changes you make to the file will persist throughout page reloads and navigating pages in the website as long as the devtools is running.</p><p>To stop overriding files on the website, go to the <strong>Overrides </strong>page again and click on the icon for "<strong>Clear configuration"</strong> and the overrides will be gone.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/devtools-4.png" class="kg-image" alt="Here's Why You Should Be Using Overrides in Chrome Devtools" loading="lazy"/></figure><hr><h2 id="conclusion">Conclusion</h2><p>Do you use Overrides when developing your website? What other tools do you think are also helpful? Let us know in the comments!</p></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Chrome Extensions Every Web Developer Needs]]></title><description><![CDATA[I have curated for you a list of Chrome extensions that will make your everyday work easier!]]></description><link>https://blog.shahednasser.com/chrome-extensions-every-programmer-needs/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e7b</guid><category><![CDATA[Browser Extensions]]></category><category><![CDATA[Beginners]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 17 Dec 2020 08:03:09 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/6ac80cdd0f2390ae8dfef9b0a25c8dbb/photo-1571171637578-41bc2dd41cd2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/6ac80cdd0f2390ae8dfef9b0a25c8dbb/photo-1571171637578-41bc2dd41cd2.jpg" alt="Chrome Extensions Every Web Developer Needs"/><p>As a web developer, you might face a lot of tedious and repetitive tasks, or tasks that can be a hassle to manually do.</p><p>I have curated for you a list of Chrome extensions that will make your everyday work easier!</p><hr><h2 id="colorzilla"><a href="https://chrome.google.com/webstore/detail/colorzilla/bhlhnicpbhignbdhedgjhgdocnmhomnp?hl=en">ColorZilla</a></h2><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/colorzilla.jpg.jpg" class="kg-image" alt="Chrome Extensions Every Web Developer Needs" loading="lazy"/></figure><p>I use ColorZilla almost every day. It's a great help to get a color from any website or image, and as a web developer you'll need that a lot. </p><hr><h2 id="pushbullet"><a href="https://chrome.google.com/webstore/detail/pushbullet/chlffgpmiacpedhhbkiomidkjlcfhogd?hl=en">Pushbullet</a></h2><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/pushbullet.jpg" class="kg-image" alt="Chrome Extensions Every Web Developer Needs" loading="lazy"/></figure><p>Pushbullet is great for all people in general, especially for work. It makes communication between your devices or team easier. You can send to your devices or team links, images, or any kind of messages. You can also check your devices' notifications and SMS.</p><hr><h2 id="gitpod"><a href="https://chrome.google.com/webstore/detail/gitpod-dev-environments-i/dodmmooeoklaejobgleioelladacbeki?hl=en">Gitpod</a></h2><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/gitpod.jpg" class="kg-image" alt="Chrome Extensions Every Web Developer Needs" loading="lazy"/></figure><p>If you don't know what <a href="https://gitpod.io/">Gitpod</a> is, it basically lets you create a remote environment for your repositories. Integrated with GitHub, you can open any repository in Gitpod and create a workspace that you can access from anywhere.</p><p>This extension helps make it easier to open any repository in Gitpod right away just by clicking on the extension icon when you are in the repository's page.</p><hr><h2 id="fake-data-a-form-filler-you-won-t-hate"><a href="https://chrome.google.com/webstore/detail/fake-data-a-form-filler-y/gchcfdihakkhjgfmokemfeembfokkajj?hl=en">Fake Data - A form filler you won't hate</a></h2><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/fake-data.jpg" class="kg-image" alt="Chrome Extensions Every Web Developer Needs" loading="lazy"/></figure><p>When you are testing your websites, testing forms repeatedly and with real looking data (i.e. not "abcd") can be time consuming. With Fake Data, you can right click on any input and choose a fake value for the input. It includes values for first names, email, city, country, password, and more. You can also add custom types and values to it from the extension's settings.</p><hr><h2 id="social-share-preview"><a href="https://chrome.google.com/webstore/detail/social-share-preview/ggnikicjfklimmffbkhknndafpdlabib?hl=en">Social Share Preview</a></h2><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/social-share-preview.jpg" class="kg-image" alt="Chrome Extensions Every Web Developer Needs" loading="lazy"/></figure><p>SEO is very important for any website, and one of the most important parts about it is how your website or webpage will look like when it is shared on social media like Facebook, Twitter, and other platforms. Social Share Preview makes it easy to check by just clicking the extension's icon on the page you want to check. It will show you a preview of how your website will look like when it is shared, and will give you some tips on how to fix problems if there are any.</p><hr><h2 id="awesome-screenshot-screen-recorder"><a href="https://chrome.google.com/webstore/detail/awesome-screenshot-screen/nlipoenfbbikpbjkfpfillcgkoblgpmj?hl=en">Awesome Screenshot & Screen Recorder</a></h2><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/awesome-screenshot.jpg" class="kg-image" alt="Chrome Extensions Every Web Developer Needs" loading="lazy"/></figure><p>This one is also not specific for programmers, however it can be helpful. This extension helps you record or screenshot the screen in your browser easily and with additional options like choosing just the visible part of the page or entire page, as well as other options.</p><hr><h2 id="html-error-checker"><a href="https://chrome.google.com/webstore/detail/html%E3%82%A8%E3%83%A9%E3%83%BC%E3%83%81%E3%82%A7%E3%83%83%E3%82%AB%E3%83%BC/ohdllebchmmponnofchalfkegpjojcaf?hl=en">HTML Error Checker</a></h2><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/html-error-checker.jpg" class="kg-image" alt="Chrome Extensions Every Web Developer Needs" loading="lazy"/></figure><p>You can't always spot HTML errors like forgetting to close a tag or closing one too early. This can affect your website and sometimes you won't even notice it until later on. This extension helps you find any errors on the website you're on.</p><p><strong>NOTE: </strong>For some reason, this extension caused some problems when trying to log in to phpmyadmin when it is pinned.</p><hr><h2 id="web-developer-checklist"><a href="https://chrome.google.com/webstore/detail/web-developer-checklist/iahamcpedabephpcgkeikbclmaljebjp?hl=en-US">Web Developer Checklist</a></h2><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/web-developer-checklist.jpg" class="kg-image" alt="Chrome Extensions Every Web Developer Needs" loading="lazy"/></figure><p>Web Developer Checklist helps you remember all the details necessary for your website. A lot of tasks when making websites can be forgotten, especially when focusing on the bigger parts. By clicking the icon of the extension on the webpage, you can see any violations to best practices.</p><hr><h2 id="webpage-spell-check"><a href="https://chrome.google.com/webstore/detail/webpage-spell-check/mgdhaoimpabdhmacaclbbjddhngchjik">Webpage Spell-Check</a></h2><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/webpage-spell-checker.jpg" class="kg-image" alt="Chrome Extensions Every Web Developer Needs" loading="lazy"/></figure><p>Typos can be hard to spot on the website. This extension enables you to check typos by making all the text on your website editable, and thus using the browser's out-of-the-box spell-checker to find the typos.</p><hr><h2 id="web-developer"><a href="https://chrome.google.com/webstore/detail/web-developer/bfbameneiokkgbdmiekhjnmfkcnldhhm">Web Developer</a></h2><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/web-developer.jpg" class="kg-image" alt="Chrome Extensions Every Web Developer Needs" loading="lazy"/></figure><p>Web Developers extension basically gives super powers in an extension. It gives you so many functionalities that can be helpful while you develop websites and remove a lot of hassles that you can run into.</p><hr><h2 id="conclusion">Conclusion</h2><p>These are just some of the extensions that can make your life as a developer a little easier, but there are many others out there. Please add any extensions you think are also helpful below in the comments!</p></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Deploy a Free Website With Jekyll and GitHub Pages]]></title><description><![CDATA[Sometimes you want to create a simple blog or website and deploy it easily, with no cost. It may seem hard but it's actually easy with Jekyll!]]></description><link>https://blog.shahednasser.com/deploy-a-website-with-jekyll-and-github-pages/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e7c</guid><category><![CDATA[Beginners]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 15 Dec 2020 10:13:56 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/41ea4d5fdb92638873e6c6f4d7eaecd0/photo-1502945015378-0e284ca1a5be.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/41ea4d5fdb92638873e6c6f4d7eaecd0/photo-1502945015378-0e284ca1a5be.jpg" alt="Deploy a Free Website With Jekyll and GitHub Pages"/><p>Sometimes you want to create a simple blog or website and deploy it easily, with no cost. It may seem hard but it's actually easy with <a href="https://jekyllrb.com/">Jekyll</a>!</p><p>If you're not familiar with Jekyll, it helps you create a simple and static websites. You can just write your content in HTML or <a href="https://daringfireball.net/projects/markdown/">Markdown</a>. </p><p>In this post I will teach you how to create a blog with Jekyll in easy steps, and then deploy it on GitHub pages for free!</p><hr><h2 id="installing-jekyll">Installing Jekyll</h2><p>To start with Jekyll, you first need to install some prerequisites on your system. You can find <a href="https://jekyllrb.com/docs/installation/">here</a> on Jekyll's website detailed guides on how you can do it based on your system.</p><p>Once you install the prerequisites, you can use the following command to install Jekyll:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">gem <span class="token function">install</span> jekyll bundler</code></pre></div><hr><h2 id="create-website">Create Website</h2><p>Now you can create your website! It takes just one command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">jekyll new tech-blog</code></pre></div><p>We're calling our website <code class="language-text">tech-blog</code>, you can replace that with whatever name you want for your website. This command will create a new folder with all the files necessary for your Jekyll website.</p><h2 id="adding-jekyll-to-an-existing-project">Adding Jekyll to An Existing Project</h2><p>The command above will create a new project from scratch. If you already have a project that you want to add Jekyll to, you can add the <code class="language-text">--force</code> option like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">jekyll new tech-blog --force</code></pre></div><p>This will add Jekyll to your existing directory <code class="language-text">tech-blog</code> that has your project.</p><hr><h2 id="build-and-start-website-locally">Build and Start Website Locally</h2><p>After creating the Jekyll website above, change the directory to be inside the website directory</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token builtin class-name">cd</span> tech-blog</code></pre></div><p>Then, build and serve the website locally with the following command:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">bundle <span class="token builtin class-name">exec</span> jekyll serve</code></pre></div><p>Then go in your browser to <code><a href="http://localhost:4000/">localhost:4000</a></code> and you will see your new blog up and running!</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/tech-blog-starter.png" class="kg-image" alt="Deploy a Free Website With Jekyll and GitHub Pages" loading="lazy"/></figure><p>By adding the option <code class="language-text">--livereload</code> to the above command, your website will live reload as you make changes to files</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">bundle <span class="token builtin class-name">exec</span> jekyll serve --livereload</code></pre></div><hr><h2 id="adding-pages">Adding Pages</h2><p>Let's try adding a new page to our website. In the root of the website's directory, create the file <code class="language-text">helloworld.md</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="markdown"><pre class="language-markdown"><code class="language-markdown"><span class="token front-matter-block"><span class="token punctuation">---</span> <span class="token front-matter yaml language-yaml">layout: page title: Hello World permalink: /hello-world/</span> <span class="token punctuation">---</span></span> Hey There!</code></pre></div><p>The lines between the three dashes are like the header of the page that define meta information about it. Here we have three information:</p><ol><li><strong>layout: </strong>It means what will be the layout of the page. By default, it can be <code class="language-text">default</code>, <code class="language-text">home</code>, <code class="language-text">page</code> or post. You can also add your own custom layouts.</li><li><strong>title: </strong>The title of the page.</li><li><strong>permalink</strong>: the url of the page.</li></ol><p>Once you add the file and save the content in it, you can refresh the page of your website and see a new link is added to the Navigation bar, or if you had <code class="language-text">--livereload</code> in your command then it will have already refreshed the page for you. Click on it and see the new page we just created.</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/hello-world.png" class="kg-image" alt="Deploy a Free Website With Jekyll and GitHub Pages" loading="lazy"/></figure><p>You can try editing the content of the file under the three dashes and see the changes.</p><p>Here, we created this page using markdown. You can also do the same thing with html files</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html">--- layout: page title: Hello World permalink: /hello-world/ --- <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span>Hey There!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre></div><hr><h2 id="adding-posts">Adding Posts</h2><p>If the website you are creating is a blog, you can add posts in the <code class="language-text">_posts</code> directory. Files for posts need to start with the date of the post in the format <code class="language-text">YYYY-MM-DD</code> then followed by the name of the post in slug format.</p><p>Create a new file <code class="language-text">_posts/2020-12-15-my-first-post.md</code> (or HTML, both can work) with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="markdown"><pre class="language-markdown"><code class="language-markdown"><span class="token front-matter-block"><span class="token punctuation">---</span> <span class="token front-matter yaml language-yaml">layout: post title: "My First Post" categories: updates</span> <span class="token punctuation">---</span></span> This is my first post. Thank you for reading it!</code></pre></div><p>Once we save it and go to our website, we will see a new post added on the home screen.</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/blog-home-page.png" width="1294" height="724" loading="lazy" alt="Deploy a Free Website With Jekyll and GitHub Pages"/></div><div class="kg-gallery-image"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/blog-post.png" width="1294" height="680" loading="lazy" alt="Deploy a Free Website With Jekyll and GitHub Pages"/></div></div></div></figure><hr><h2 id="changing-website-information">Changing Website Information</h2><p>To change your website/blog's information like title or URL, all meta information is included in the <code class="language-text">_config.yml</code> file. </p><p>The <code class="language-text">_config.yml</code> file by default has the following keys:</p><ol><li><strong>title: </strong>The title of the website.</li><li><strong>email: </strong>Contact email that will also appear in the footer.</li><li><strong>description: </strong>Description of the website. Will also appear in the footer.</li><li><strong>baseurl: </strong>The subpath of the website, for example <code class="language-text">/blog</code></li><li><strong>url: </strong>The URL of the website</li><li><strong>twitter_username: </strong>Your twitter username, which will appear in the footer.</li><li><strong>github_username: </strong>Your GitHub username, which will appear in the footer.</li><li><strong>theme: </strong>the theme of your website. By default it's minima.</li><li><strong>plugins: </strong>The plugins you will use on your website. By default there's only jekyll-feed.</li></ol><p>For a full list of configurations, check them on <a href="https://jekyllrb.com/docs/configuration/">Jekyll's website</a>. Also, Minima have <a href="https://github.com/jekyll/minima/tree/v2.5.1">additional configuration</a> as well.</p><p>Let's try changing the website title:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">title</span><span class="token punctuation">:</span> Tech Blog</code></pre></div><p>Changes to <code class="language-text">_config.yml</code> will not be shown by refreshing or through live reload. You need to restart the server.</p><p>If you restart the server and go to the website now, you will see that the website name has changed in the navigation bar, footer, and anywhere else it might be used.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/website-title.png" class="kg-image" alt="Deploy a Free Website With Jekyll and GitHub Pages" loading="lazy"/></figure><hr><h2 id="making-changes-to-home-page">Making Changes to Home Page</h2><p>All changes in the Home page should be made in <code class="language-text">index.markdown</code>. By default, it uses the home layout which shows the list of posts you have. However, you can change the layout of the page or add any additional content to it.</p><p>Let's try adding some content to it:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="md"><pre class="language-md"><code class="language-md"><span class="token front-matter-block"><span class="token punctuation">---</span> <span class="token front-matter yaml language-yaml"># Feel free to add content and custom Front Matter to this file. # To modify the layout, see https://jekyllrb.com/docs/themes/#overriding-theme-defaults layout: home</span> <span class="token punctuation">---</span></span> This is my tech blog</code></pre></div><p>Everything between the dashes is already there by default. We just added the line "This is my tech blog". If you go to your website now, you will find that this line has been added above the posts.</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/change-homepage.png" class="kg-image" alt="Deploy a Free Website With Jekyll and GitHub Pages" loading="lazy"/></figure><hr><h2 id="using-assets">Using Assets</h2><p>Any assets that you add in the root of the directory will automatically be included in the Jekyll build. These include CSS and Javascript files or images.</p><p>To add CSS to your website, you have two options:</p><ol><li>Copy the content of main.css in the <code class="language-text">_site</code> directory, then create a new file in the root of your directory <code class="language-text">assets/main.css</code> with the content you copied. Then you can make any additions to it and it will be shown.</li><li>Create a new file and add it to the head of the website.</li></ol><p>To do it with the second method, first create the file <code class="language-text">assets/styles.css</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.site-title, .site-title:visited</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> #f00<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>We're just changing the color of the title here. Then, we need to include it in the <code class="language-text"><head></code> of the website. To do that, you need to copy the content of <code><a href="https://github.com/jekyll/minima/blob/v2.5.1/_includes/head.html">includes/head.html</a></code> from minima (or whatever theme you are using), then create <code class="language-text">_includes/head.html</code> in your root directory with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>IE=edge<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> {%- seo -%} <link rel="stylesheet" href="{{ "/assets/main.css" | relative_url }}"> {%- feed_meta -%} {%- if jekyll.environment == 'production' and site.google_analytics -%} {%- include google-analytics.html -%} {%- endif -%} <link rel="stylesheet" href="{{ "/assets/styles.css" | relative_url }}"> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span></code></pre></div><p>Everything before the last line is from the minima theme. The last line is what we added, which is a link to the stylesheet we created <code class="language-text">assets/styles.css</code>.</p><p>If you go to the website now, you'll find that the color of the title of the page has changed.</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/site-title.png" class="kg-image" alt="Deploy a Free Website With Jekyll and GitHub Pages" loading="lazy"/></figure><h3 id="optional-using-sass">Optional: Using Sass</h3><p>You can also use Sass instead of CSS. To do this, first you need to add the following to <code class="language-text">_config.yml</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">sass</span><span class="token punctuation">:</span> <span class="token key atrule">sass_dir</span><span class="token punctuation">:</span> assets <span class="token key atrule">style</span><span class="token punctuation">:</span> compressed</code></pre></div><p><code class="language-text">sass_dir</code> is necessary if you are using imports inside sass files.</p><p>Then, create the file <code class="language-text">assets/styles.sass</code> with the following content:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="sass"><pre class="language-sass"><code class="language-sass"><span class="token selector">---</span> <span class="token selector">---</span> <span class="token selector">.site-title, .site-title:visited</span> <span class="token property-line"> <span class="token property">color</span><span class="token punctuation">:</span> #f00</span></code></pre></div><p>The first two dash lines tells Jekyll to compile and add this file to the build. After that, you can add any styles you need.</p><p>Finally, we need to import it in the <code class="language-text"><head></code> of the page. The previous head code can be used, as <code class="language-text">assets/styles.sass</code> will be compiled to <code class="language-text">assets/styles.css</code>.</p><p>If you now refresh the page, you'll see that the site title color is red.</p><hr><h2 id="deploying-to-github-pages">Deploying to GitHub Pages</h2><p>Once you are done making the website, you can now deploy it on GitHub pages for free.</p><p>First, you need to have a repository for your website on GitHub. If not, then create one and commit your work to it.</p><p>Next, go to Settings and scroll down to GitHub Pages</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/github-pages-settings.png" class="kg-image" alt="Deploy a Free Website With Jekyll and GitHub Pages" loading="lazy"/></figure><p>Here, you will need to pick a Source branch and then the root directory. Click Save, and GitHub will start compiling your website.</p><p>However, it will not work right away. There are some changes you need to make in the website.</p><p>In <code class="language-text">_config.yml</code> you need to change three key values:</p><ol><li><strong>baseurl: </strong>this needs to be the subpath of the website</li><li><strong>url: </strong>this is the main URL of the website.</li><li><strong>destination: </strong>The directory in which the build goes to</li></ol><p>When creating a website in GitHub pages, usually the format of the URL will be: <strong>https://USERNAME.github.io/REPOSITORY-NAME</strong></p><p>So, <code class="language-text">baseurl</code> should be <code class="language-text">/REPOSITORY-NAME</code> part of your URL, and <code class="language-text">url</code> should be <code class="language-text">https://USERNAME.github.io</code><strong> </strong>part of your URL.</p><p>Since we are deploying this to GitHub pages, by default it uses the content of <code class="language-text">docs</code> directory in your repository. So, add a <code class="language-text">destination</code> key in <code class="language-text">_config.yml</code> and set it to <code class="language-text">./docs</code></p><div class="kg-card kg-code-card gatsby-highlight" data-language="yml"><pre class="language-yml"><code class="language-yml"><span class="token key atrule">destination</span><span class="token punctuation">:</span> ./docs</code></pre></div><p>Then create a <code class="language-text">docs</code> directory. But we don't want the content of docs to be available in the repository. So, create an empty <code class="language-text">.gitkeep</code> file in it. This is necessary to make sure that the docs directory can be committed to the repository. Then, add the following to <code class="language-text">.gitignore</code>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">docs/* !docs/.gitkeep</code></pre></div><p>This will make sure that the content of the <code class="language-text">docs</code> directory will not be added except for <code class="language-text">.gitkeep</code>.</p><p>Once you commit and push all these changes to your repository, your GitHub Pages will be built again and once it's done you can view it on your designated URL!</p><hr><h2 id="conclusion">Conclusion</h2><p>So many additional settings and configurations can go into creating your Jekyll website. This tutorial aims to keep it as simple as possible. You can check out <a href="https://jekyllrb.com/docs/">Jekyll's website</a> for documentation on how to create or choose different Themes, Plugins, and more!</p></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[CSS Generators That Will Make Your Life Easier]]></title><description><![CDATA[Whether you've been working in Web Development forever or you're just a beginner, so many styles that you have to implement using CSS can be a pain. ]]></description><link>https://blog.shahednasser.com/css-generators-that-will-make-life-easier/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e7a</guid><category><![CDATA[CSS]]></category><category><![CDATA[Design]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 10 Dec 2020 09:54:44 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/3702d583dc5ef9b1de6e01b38fa53200/photo-1518085250887-2f903c200fee.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/3702d583dc5ef9b1de6e01b38fa53200/photo-1518085250887-2f903c200fee.jpg" alt="CSS Generators That Will Make Your Life Easier"/><p>Whether you've been working in Web Development forever or you're just a beginner, so many styles that you have to implement using CSS can be a pain. </p><p>To make your life easier, I've compiled a list of generators that will make CSS a little more pleasant for you.</p><hr><h2 id="animista"><a href="https://animista.net/">Animista</a></h2><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/animista.png" class="kg-image" alt="CSS Generators That Will Make Your Life Easier" loading="lazy"/></figure><p><a href="https://animista.net/">Animista</a> helps you generate animations in CSS. Its visualization and variety of options put your mind at ease, as you can rely on it to do it all for you. Even if the animation you are going for is pretty simple, it's still nice to waste less time on it.</p><hr><h2 id="box-shadow-css-generator"><a href="https://cssgenerator.org/box-shadow-css-generator.html">Box Shadow CSS Generator</a></h2><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/box-shadow-generator.png" class="kg-image" alt="CSS Generators That Will Make Your Life Easier" loading="lazy"/></figure><p>This generator helps you create box shadows for elements. It's very simple to use and can be of great help, especially for beginners.</p><hr><h2 id="css-triangle-generator"><a href="http://apps.eky.hk/css-triangle-generator/">CSS Triangle Generator</a></h2><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/triangle-generator.png" class="kg-image" alt="CSS Generators That Will Make Your Life Easier" loading="lazy"/></figure><p>One of the most annoying things you have to learn while using CSS is probably creating an arrow on one of the element's sides, and you can't run away from it. It's used in almost every website. This generator makes it easier to do it and saves you the hassle.</p><hr><h2 id="css3-text-shadow-generator"><a href="https://css3gen.com/text-shadow/">CSS3 Text Shadow Generator</a></h2><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/text-shadow-generator.png" class="kg-image" alt="CSS Generators That Will Make Your Life Easier" loading="lazy"/></figure><p>If you are in need to create a text-shadow but you're not sure how, or you're just too lazy to do it yourself, this generator is here to help! You can see the text as you are modifying it, so it will be easier to choose the style you want and implement it.</p><hr><h2 id="bubbler"><a href="https://www.ilikepixels.co.uk/bubbler/">Bubbler</a></h2><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/bubbler.png" class="kg-image" alt="CSS Generators That Will Make Your Life Easier" loading="lazy"/></figure><p>Bubbler helps you create speech bubbles with ease. You can choose from a lot of configurations like color, size, arrow location, etc...</p><hr><h2 id="css-gradient"><a href="https://cssgradient.io/">CSS Gradient</a></h2><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/css-gradient-generator.png" class="kg-image" alt="CSS Generators That Will Make Your Life Easier" loading="lazy"/></figure><p>CSS gradients can be hard for a lot of people, not just to create it but to make it visually pleasing, and to make it work cross-browser. This generator lets you play around with colors until you find the gradient that looks good for you and provides you with cross-browser code that will put your mind at ease.</p><hr><h2 id="coolors"><a href="https://coolors.co/d5b0ac-cea0ae-684551-402e2a-9cd08f">Coolors</a></h2><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/coolers.png" class="kg-image" alt="CSS Generators That Will Make Your Life Easier" loading="lazy"/></figure><p>This is not CSS specific, but it’s also pretty helpful. For a lot of people (including myself) picking the color theme of the website can be a difficult task and a lot of times makes us want to give up the website altogether. Coolors generates color palettes that are modern and look good. You can easily navigate between patterns by just clicking the spacebar!</p><hr><h2 id="background-image-generator"><a href="http://bg.siteorigin.com/">Background Image Generator</a></h2><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/siteorigin-bg.png" class="kg-image" alt="CSS Generators That Will Make Your Life Easier" loading="lazy"/></figure><p>SiteOrigin brings us a creative tool that will definitely make your website unique! Through their Background Image Generator tool, you can create a background image for your website with different patterns and colors. Although their end result is an image to download, it still beats having to create it with CSS yourself.</p><hr><h2 id="zenbg"><a href="https://galactic.ink/bg/">ZenBG</a></h2><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/zen-bg.png" class="kg-image" alt="CSS Generators That Will Make Your Life Easier" loading="lazy"/></figure><p>With ZenBG you can also generate background images with different colors and patterns and features, however, it has some additional features that make it good as well. First, you can load your website and edit it live to see how it will look like. This is better than having to copy the CSS to your website and keep going back and forth until you get it right. Another good thing about it is that you can choose gradients. In addition, you can choose to get the CSS code or download the wallpaper as an image.</p><hr><h2 id="css-media-query-generator"><a href="https://simplecss.eu/">CSS Media Query Generator</a></h2><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/media-query-generator.png" class="kg-image" alt="CSS Generators That Will Make Your Life Easier" loading="lazy"/></figure><p>For everyone that still struggles with getting media queries right and provide support for different devices, this generator got you covered! You can choose the device type like phone, laptop, or desktop, but you can also choose specific devices like the iPhone 6s. Their devices data set is a little outdated but it can still be helpful in a lot of cases.</p><hr><h2 id="buttons-generator"><a href="https://markodenic.com/tools/buttons-generator/">Buttons Generator</a></h2><figure class="kg-card kg-image-card"><img src="https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-06-at-9.35.53-PM.png" class="kg-image" alt="CSS Generators That Will Make Your Life Easier" loading="lazy" width="2000" height="1252" srcset="https://backend.shahednasser.com/content/images/size/w600/2021/10/Screen-Shot-2021-10-06-at-9.35.53-PM.png 600w, https://backend.shahednasser.com/content/images/size/w1000/2021/10/Screen-Shot-2021-10-06-at-9.35.53-PM.png 1000w, https://backend.shahednasser.com/content/images/size/w1600/2021/10/Screen-Shot-2021-10-06-at-9.35.53-PM.png 1600w, https://backend.shahednasser.com/content/images/size/w2400/2021/10/Screen-Shot-2021-10-06-at-9.35.53-PM.png 2400w" sizes="(min-width: 720px) 720px"/></figure><p>This tool created by <a href="https://twitter.com/denicmarko">Marko Denic</a> allows you to easily copy the CSS of neat buttons of different kinds. There are 3D buttons, Gradient buttons, Retro buttons, and more kinds that you can easily add to your website using this generator.</p><hr><h2 id="conclusion">Conclusion</h2><p>Do you find these generators helpful? And do you use any other generators that are not mentioned here? Mention them in the comments below!</p></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Fun Google Tricks to Try When You're Bored]]></title><description><![CDATA[Google is the best search engine that we all use. Not only does it help us find what we need, but it gives us nice funny tricks to try when we're bored!]]></description><link>https://blog.shahednasser.com/fun-google-tricks-to-try-when-youre-bored/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e79</guid><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 07 Dec 2020 11:57:01 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/ac4d8a92057297fd689566be0039ed6a/photo-1573804633927-bfcbcd909acd--1-.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/ac4d8a92057297fd689566be0039ed6a/photo-1573804633927-bfcbcd909acd--1-.jpg" alt="Fun Google Tricks to Try When You're Bored"/><p>Google is the best search engine that we all use. Not only does it help us find what we need, but it gives us nice funny tricks to try when we're bored!</p><p>Scroll through the list and try these tricks out!</p><hr><h2 id="askew"><a href="https://www.google.com/search?q=askew">Askew</a></h2><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/askew-Google-Search.png" class="kg-image" alt="Fun Google Tricks to Try When You're Bored" loading="lazy"/></figure><p>Just type in "askew" in the search bar, and Google will become askew!</p><h2 id="recursion"><a href="https://www.google.com/search?q=recursion">Recursion</a></h2><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/recursion-Google-Search.png" class="kg-image" alt="Fun Google Tricks to Try When You're Bored" loading="lazy"/></figure><p>This one is funny for you if you're a programmer. Type in recursion and Google will ask you again: "Did you mean recursion?"</p><h2 id="do-a-barrel-roll"><a href="https://www.google.com/search?q=do+a+barrel+roll">Do a Barrel Roll</a></h2><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screenshot-from-2020-11-27-15-30-31.png" class="kg-image" alt="Fun Google Tricks to Try When You're Bored" loading="lazy"/></figure><p>Type in "Do a Barrel Roll" and see Google spinning!</p><h2 id="blink-html"><a href="https://www.google.com/search?q=blink+html">Blink HTML</a></h2><figure class="kg-card kg-image-card"><img src="https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/ibZ8QjS.gif" class="kg-image" alt="Fun Google Tricks to Try When You're Bored" loading="lazy"/></figure><p>Type in "Blink HTML" and see the word "HTML" blinking everywhere!</p><h2 id="pacman"><a href="https://www.google.com/search?q=pacman">Pacman</a></h2><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screenshot-from-2020-12-01-15-49-12.png" class="kg-image" alt="Fun Google Tricks to Try When You're Bored" loading="lazy"/></figure><p>By searching "pacman", you can play the Pac-man game! It's a nice throwback.</p><h2 id="google-in-1998"><a href="https://www.google.com/search?q=google+in+1998">Google in 1998</a></h2><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screenshot-from-2020-12-02-09-40-19.png" class="kg-image" alt="Fun Google Tricks to Try When You're Bored" loading="lazy"/></figure><p>Feeling nostalgic or curious about how Google used to look like? Google lets you turn back time by googling "Google in 1998"!</p><h2 id="set-a-timer"><a href="https://www.google.com/search?q=set+timer+for+1+minute">Set a Timer</a></h2><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screenshot-from-2020-12-02-09-43-17.png" class="kg-image" alt="Fun Google Tricks to Try When You're Bored" loading="lazy"/></figure><p>Google lets you set a timer for any amount of time you need and will alert you once the time is up! Just google "Set timer for" and specify the amount of time. For example, "set timer for 1 minute"</p><h2 id="flip-a-coin"><a href="https://www.google.com/search?q=flip+a+coin">Flip a coin</a></h2><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screenshot-from-2020-12-02-09-45-18.png" class="kg-image" alt="Fun Google Tricks to Try When You're Bored" loading="lazy"/></figure><p>Need to make some quick decisions? Google can help you! Just search "Flip a Coin" and google will do exactly that.</p><h2 id="roll-a-die"><a href="https://www.google.com/search?q=roll+a+die">Roll a Die</a></h2><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screenshot-from-2020-12-02-10-02-12.png" class="kg-image" alt="Fun Google Tricks to Try When You're Bored" loading="lazy"/></figure><p>Another trick Google can do is roll a dice for you! Google "Roll a die" and you can choose from multiple die sizes!</p><h2 id="special-friends-tribute"><a href="https://www.google.com/search?q=joey+friends">Special Friends Tribute</a></h2><p>This one is special for Friends fans: If you google "friends" followed by one of the main character names, you will get an icon next to the name that is relevant to that character and when you press it a surprise happens!</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screenshot-from-2020-12-02-10-19-18.png" class="kg-image" alt="Fun Google Tricks to Try When You're Bored" loading="lazy"/></figure><p>For example, for Joey you can see a Pizza icon next to his name and when you press it, food will start flying around until a hand comes up and collects all the food!</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screenshot-from-2020-12-02-10-19-21.png" class="kg-image" alt="Fun Google Tricks to Try When You're Bored" loading="lazy"/></figure><hr><h2 id="conclusion">Conclusion</h2><p>Do you have any tricks that you've noticed or known about that aren't on the list? Let us know in the comments!</p></hr></hr>]]></content:encoded></item><item><title><![CDATA[How to Setup Previews For PRs on Your GitHub Repo Using Netlify]]></title><description><![CDATA[Netlify helps you generate previews for every PR you receive on your Repository for free and the setup is very simple!]]></description><link>https://blog.shahednasser.com/how-to-setup-previews-for-prs-on-your-github-repo/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e78</guid><category><![CDATA[Open Source]]></category><category><![CDATA[Tips]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 03 Dec 2020 09:00:09 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/576a3debae1f2e5978e9669940a85a40/netlify-logo.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: html--><div class="suggested-read"><img src="https://blog.shahednasser.com/static/576a3debae1f2e5978e9669940a85a40/netlify-logo.png" alt="How to Setup Previews For PRs on Your GitHub Repo Using Netlify"/><p style="margin-bottom: 0;">This blog has been mentioned as one of Feedspot's <a href="https://blog.feedspot.com/programming_blogs/" target="_blank">Top 100 Programming Blogs</a>. </p></div><!--kg-card-end: html--><p>It's a big hassle for maintainers to set up and check every pull request that is created on their Repository, especially when the repository becomes popular or during Hacktoberfest. </p><p>Netlify helps you generate previews for every PR you receive on your Repository for free and the setup is very simple!</p><hr><h2 id="create-a-netlify-account">Create a Netlify Account</h2><p>Head to <a href="https://app.netlify.com/signup?_ga=2.186805096.1187265105.1606308521-719326085.1601620184">Netlify</a> to create an account. You can choose to Sign up with GitHub, GitLab, Bitbucket, or email. Choosing Sign up with GitHub is the fastest way, as you can directly give it access to your repositories.</p><hr><h2 id="create-a-new-site">Create a New Site</h2><p>Once you create an account, you will be prompted to create a new site. You will first need to choose the Git Provider you are using. In our case, it's GitHub.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screenshot-from-2020-11-25-14-51-55.png" class="kg-image" alt="How to Setup Previews For PRs on Your GitHub Repo Using Netlify" loading="lazy"/></figure><p>A new window will open asking you to authorize Netlify to access your GitHub repositories. </p><p>The next step would be to choose the repository you want to show the previews on. You will be given a list of your repositories to choose from.</p><p>After you choose your repository, you will be asked to choose the branch.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screenshot-from-2020-11-25-14-55-32.png" class="kg-image" alt="How to Setup Previews For PRs on Your GitHub Repo Using Netlify" loading="lazy"/></figure><p>You will also be asked to add some build settings:</p><ol><li><strong>Build Command: </strong>The command that is necessary to run on the project for it to be ready for production. If you are using some frameworks or development dependencies, or your project needs something to be done before it is ready to be published publicly, you need to create a script for it and enter the command here. For example, if you are using npm and you have a build script, you should enter here <code class="language-text">npm run build</code></li><li><strong>Publish Directory: </strong>If your repository has a publish directory like <code class="language-text">build</code>, <code class="language-text">public</code> or static then it should be entered here. Otherwise, the root of the repository will be published for production.</li></ol><p>If there are some environment variables you need to add for configuration purposes, you can click "Show Advanced", then click "New Variable and start adding variables and their values.</p><p>Once you are done, click Deploy Site. You will be redirected to the new dashboard for your site showing you details about the current deployment and other information as well.</p><p>You will notice that your project will be given a random URL and name. For example, determined-goodall-351866. You can change the domain settings and enter a custom domain if you have one.</p><hr><h2 id="generate-build-previews-for-prs">Generate Build Previews For PRs</h2><p>Go to Site Settings and choose "Build & deploy" from the sidebar. Then scroll down to "Deploy notifications".</p><figure class="kg-card kg-image-card"><img src="https://res-2.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screenshot-from-2020-11-25-15-11-42.png" class="kg-image" alt="How to Setup Previews For PRs on Your GitHub Repo Using Netlify" loading="lazy"/></figure><p>Then, click on the "Add notification" dropdown and select "GitHub Pull Request Comment". A new window will open that will ask you to choose the event on which the comment should be added. Choose "Deploy Preview succeeded".</p><p>Next, you can choose the comment that will be shown. This comment will be alongside the URL of the custom generated URL. Enter some comment like "Your Preview is Ready!".</p><p>Once you are done click Save.</p><hr><h2 id="conclusion">Conclusion</h2><p>After completing the steps above, a preview will be generated for every new PR and you will see a comment on the PR with the URL where you can check out the preview.</p></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Localizing Your Chrome Extension: An Easy Tutorial]]></title><description><![CDATA[Localization and Internationalization is a great way to get more users for your extension. Here is a simple tutorial that will help you do that.]]></description><link>https://blog.shahednasser.com/localizing-your-chrome-extension-an-easy-tutorial/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e76</guid><category><![CDATA[Browser Extensions]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 26 Nov 2020 11:02:19 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/a5dee5a349ef15fdc1df24910cbc4e39/chrome-logo.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/a5dee5a349ef15fdc1df24910cbc4e39/chrome-logo.jpg" alt="Localizing Your Chrome Extension: An Easy Tutorial"/><p>Localization and Internationalization is a great way to get more users for your extension. Here is a simple tutorial that will help you do that.</p><p><strong>This tutorial assumes you already know how to create a chrome extension. If not, you can head to my <a href="https://shahednasserblog.tk/chrome-extension-tutorial-replace-images-in-any-website-with-pikachu/">other tutorial</a> to learn how to do that.</strong></p><hr><h2 id="step-1-changing-manifest-json">Step 1: Changing Manifest.json</h2><p>When localizing your extension, you need to pick a default locale. This needs to be defined in the <code class="language-text">manifest.json</code> file:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> ... <span class="token property">"default_locale"</span><span class="token operator">:</span> <span class="token string">"en"</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span></code></pre></div><p>You need to add a new key <code class="language-text">default_locale</code> and the value should be the locale that your extension will default to. In the example above we chose <code class="language-text">en</code> for English.</p><p>You can check the list of supported locales <a href="http://code.google.com/chrome/webstore/docs/i18n.html#localeTable">here</a>. If you pick a locale that's not supported, Chrome will ignore it.</p><h2 id="step-2-translation-strings">Step 2: Translation Strings</h2><p>Next thing you need to do is start creating the JSON files that will hold the localizable strings in your extension. </p><p>You will need to first create the directory <code class="language-text">locales</code> in the root of your extension. Then inside that directory, you will be creating a folder for each locale that will hold the JSON file with the string translations for each locale. For example, to add the string translations for the English locale <code class="language-text">en</code>, you will need to create the directory <code class="language-text">en</code> inside <code class="language-text">_locales</code> , then create <code class="language-text">messages.json</code> inside it.</p><p>You don't have to create the <code class="language-text">messages.json</code> file for every language, and you don't have to translate all the strings for every language. The only thing that is required is to have the default locale's strings. Then for any other language, if a message isn't translated for that locale, it will just default to the string in the default locale.</p><p>So, based on the previous example, we need to create the file <code class="language-text">_locales/en/messages.json</code> and place the strings that we will need to translate throughout the extension.</p><p>The format for <code class="language-text">messages.json</code> file is as follows:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"KEY"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"message"</span><span class="token operator">:</span> <span class="token string">"VALUE"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> ... <span class="token punctuation">}</span></code></pre></div><p>For each string you want to translate, you need to specify the <code class="language-text">KEY</code> and then the value for it will be an object with key <code class="language-text">message</code> and the value of it will be the string in this locale.</p><p>For example, If I want to add the string "Hello":</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"greeting"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"message"</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>Here, I am defining the key <code class="language-text">greeting</code> and that its value in the English locale will be "Hello".</p><p>You can also add an optional key <code class="language-text">description</code>. This is only helpful if you want others to translate your string and you can give them some context on when this message is used or how it should be translated.</p><p>What if we want to pass a parameter to the translation string that shouldn't be translated? Let's say I want to greet the user by their name. For example, "Hello, John".</p><p>To add parameters to the string, the string object should look like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">{ "greeting": { "message": "Hello, $USERNAME$", "placeholder": { "username": { "content": "$1" } } } }</code></pre></div><p>Here's what we did:</p><ol><li>We used <code class="language-text">$USERNAME</code> for the name of the parameter in <code class="language-text">message</code></li><li>We added a new key in the <code class="language-text">greeting</code> object which is <code class="language-text">placeholder</code>. <code class="language-text">placeholder</code> is an object that has objects in it with the key being the name of the parameter present in message, and the value of each one has the key <code class="language-text">content</code> which defines the value of the parameter.</li><li>Using <code class="language-text">$1</code> in content means it will be the first parameter passed to the translation function (we will talk about this soon). The value can be something like <code class="language-text">$2</code> (second parameter), <code class="language-text">$3</code> (third parameter), or just a string like "John". If no value is passed in the translation function, <code class="language-text">$USERNAME</code> will just be replaced by an empty string.</li></ol><p>Each object in <code class="language-text">placeholder</code> can also have an optional key <code class="language-text">example</code> as to what the parameter value can be. For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> ... <span class="token property">"username"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"content"</span><span class="token operator">:</span> <span class="token string">"$1"</span><span class="token punctuation">,</span> <span class="token property">"example"</span><span class="token operator">:</span> <span class="token string">"John"</span> <span class="token punctuation">}</span> ... <span class="token punctuation">}</span></code></pre></div><p>This is, like the <code class="language-text">description</code> key explained above, can be helpful for anyone translating this extension to understand what the parameter passed to the message could be.</p><p>Let's say we want to add now the translation for the Spanish language. We need to create the file <code class="language-text">locales/es/messages.json</code>. Note that we created a new folder <code class="language-text">es</code> in <code class="language-text">_locales</code>.</p><p>Then inside the <code class="language-text">messages.json</code> file we will have the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"greeting"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"message"</span><span class="token operator">:</span> <span class="token string">"Hola"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><p>We need to use the same key we used in the default locale which is <code class="language-text">greeting</code>, as we will later use it to fetch the string based on the locale. Then for <code class="language-text">message</code> we use the translation for the Spanish language.</p><p>Note that if you use a parameter you also need to place it here. For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"greeting"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"message"</span><span class="token operator">:</span> <span class="token string">"Hola, $USERNAME"</span><span class="token punctuation">,</span> <span class="token property">"placeholder"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"username"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"content"</span><span class="token operator">:</span> <span class="token string">"$1"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div><h2 id="step-3-use-the-localized-strings">Step 3: Use The Localized Strings</h2><h3 id="in-js-files-">In JS files:</h3><p>To get the localized string in JS files, you need to use the function <code class="language-text">chrome.i18n.getMessage</code>. For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>i18n<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token string">'greeting'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>The value will be the translation of the key <code class="language-text">greeting</code> in the current locale. If the translation is not present, the value in the default locale will be used.</p><p>If you want to pass a parameter, you can pass it as the second parameter:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">chrome<span class="token punctuation">.</span>i18n<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token string">'greeting'</span><span class="token punctuation">,</span> <span class="token string">'John'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Note that if you want to pass multiple parameters you should use an array.</p><h3 id="in-manifest-json-and-css-files">In manifest.json and CSS files</h3><p>To use a localized string in <code class="language-text">manifest.json</code> and CSS files, you need to precede the name of the string with <code class="language-text">__MSG_</code> and then follow it with <code class="language-text">__</code>. For example :</p><div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> ... <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"__MSG_greeting__"</span> ... <span class="token punctuation">}</span></code></pre></div><p><code class="language-text">__MSG_greeting__</code> will place the translation for the key <code class="language-text">greeting</code>.</p><h3 id="localization-in-html-files">Localization in HTML files</h3><p>In order to translate a string in HTML files, you need to do it manually using javascript.</p><p>Here’s how you can do it with vanilla Javascript:</p><!--kg-card-begin: html--><script src="https://gist.github.com/shahednasser/92521ac009e679fcab0eac146e1b640e.js"/><!--kg-card-end: html--><p>You can also do it with jQuery:</p><!--kg-card-begin: html--><script src="https://gist.github.com/shahednasser/3a5c1c74e7c9b2d6cfcd3c2fbfce1fea.js"/><!--kg-card-end: html--><h3 id="step-4-optional-changing-the-css-direction-based-on-the-locale">Step 4 (optional): Changing the CSS Direction Based on The Locale</h3><p>When you are localizing your extension, you might need to change the styling based on the language. Most importantly, making your extension compatible with RTL and LTR languages.</p><p>Chrome’s Internationalization system provides some messages or variables that are helpful throughout localizing your extension. The ones that will be especially helpful in CSS are:</p><ol><li><strong>@@bidi_dir: </strong>The direction based on the current locale (value will be either <strong>rtl</strong> or <strong>ltr</strong>)</li><li><strong>@@bidi_reversed_dir: </strong>The reverse of the current direction. So if the value of <code class="language-text">@@bidi_dir</code> is rtl, the value of <code class="language-text">@@bidi_reversed_dir</code> will be ltr, and vise versa.</li><li><strong>@@bidi_start_edge: </strong>If the value of <code class="language-text">@@bidi_dir</code> is rtl, the value will be right; else, it will be left.</li><li><strong>@@bidi_end_edge: </strong>If the value of <code class="language-text">@@bidi_dir</code> is rtl, the value will be left; else, it will be left. It's basically the opposite of <code class="language-text">@@bidi_start_edge</code>.</li></ol><p>These messages are helpful in your CSS as you can use them when styling your extension. For example:</p><p>extension. For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">html</span> <span class="token punctuation">{</span> <span class="token property">direction</span><span class="token punctuation">:</span> __MSG_@<span class="token atrule"><span class="token rule">@bidi_dir__</span><span class="token punctuation">;</span></span> //The direction will change based on the current locale <span class="token punctuation">}</span></code></pre></div><p>Make sure to precede every message in CSS with <code class="language-text">__MSG_</code> and follow it with <code class="language-text">__</code></p><p>There are additional provided messages:</p><ol><li><strong>@@extension_id: </strong>The id of your extension. You can’t use it in <code class="language-text">manifest.json</code></li><li><strong>@@ui_locale: </strong>The current locale.</li></ol><hr><h3 id="conclusion">Conclusion</h3><p>After following the steps above, your chrome extension will be localized and ready for users of different languages!</p></hr></hr>]]></content:encoded></item><item><title><![CDATA[Magento vs Prestashop: Which Should You Use for Your Next eCommerce Website]]></title><description><![CDATA[eCommerce websites are essential these days. Picking the correct platform to use is very important. Here's a simple list to help you]]></description><link>https://blog.shahednasser.com/magento-vs-prestashop-which-should-you-use-for-your-next-ecommerce-website/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e75</guid><category><![CDATA[Magento]]></category><category><![CDATA[PHP]]></category><category><![CDATA[eCommerce]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Fri, 20 Nov 2020 07:48:44 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/b9ecd7ea55f32794b2b710f0f481dc57/photo-1563013544-824ae1b704d3.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/b9ecd7ea55f32794b2b710f0f481dc57/photo-1563013544-824ae1b704d3.jpg" alt="Magento vs Prestashop: Which Should You Use for Your Next eCommerce Website"/><p>eCommerce websites are one of the most important websites and businesses these days. Picking the correct platform to use for your business or client’s business is very important. You need to pick what suits your products best, or if you have a lot of custom development that you will need to do, you need to pick the correct platform that won’t be a pain in the process.</p><p>Magento 2 and Prestashop are one of the most popular eCommerce frameworks. They both provide a solid set of features and each has its own pros and cons.</p><p>So which should you pick for your next project? You’ve probably seen many lists that made it complicated or confused you more. We’re going to compare them in a simple way that will help you easily decide which direction should you go next.</p><p>These points I am discussing below are based on my experience of working on each of these and on what clients want out of them. If you don’t want to read it all in detail, go to the <a href="https://shahednasserblog.tk/magento-vs-prestashop-which-should-you-use-for-your-next-ecommerce-website/#conclusion" rel="noopener">conclusion</a> right away.</p><hr><h3 id="pricing">Pricing</h3><p>You can use both Magento 2 and Prestashop for free. However, Magento 2 has a community edition (free) and a commerce edition (not free), and some features in the commerce edition are not available in the community edition. For most businesses, the features needed can all be found in the community edition as it has many important features out-of-the-box.</p><p><strong>Who wins? </strong>It’s a tie.</p><h3 id="out-of-the-box-features">Out-of-The-Box Features</h3><p>There’s no denying that Magento 2 comes with a set of features that overshadows Prestashop. For many businesses, the features in Magento 2 is enough to start selling as it is.</p><p>Prestashop has a good set of features as well, however, compared to Magento 2 it does lack here and there. However, if Prestashop ticks all of your checkboxes with the exception of some small features, you can easily get an extension from the <a href="https://addons.prestashop.com/en/" rel="noopener">Prestashop Marketplace</a>, but this would count as additional costs.</p><p><strong>Who wins? </strong>Magento</p><h3 id="admin-dashboard">Admin Dashboard</h3><p>Yes, Magento has a big set of features. However, we can’t completely count that as a pro, because all of these features are packed together in an Admin Dashboard that is confusing and complicated to any non-tech savvy person. Even for tech-savvy people, it needs a little to get used to it. If you consider using Magento, you probably will need to provide training for your client, and even that might not be enough for some.</p><p>Prestashop’s dashboard is very simple and straightforward. You’re looking for your orders? Just click on orders in the sidebar. Looking for products? Just click on catalog in the sidebar and you’ll find it right there. Prestashop’s to-the-point features make it easier for anyone using the dashboard to get to whatever they are looking for. For clients, that is a big pro.</p><p><strong>Who wins?</strong> Prestashop</p><h3 id="website-speed">Website Speed</h3><p>The end result of using both platforms will provide a fast website for you. However, Magento will require a lot of configuration to get that final result. From using Redis cache and Varnish cache to bundling assets among other configurations, you will need a whole task for it. On one of the projects I’ve worked on and after a few days of working on it to completely optimize everything, We reached 94 on Google’s Page Speed, which is very good.</p><p>With Prestashop, you can easily set up cache and make the website faster. However, is it as fast as Magento after the configurations? No. Magento’s configuration may be complicated, but it will provide a faster website.</p><p><strong>Who wins? </strong>Magento</p><h3 id="ease-of-development">Ease of Development</h3><p>Development in Magento can be a nightmare. The architecture of the system and how it handles modules and assists can be very confusing for beginners or anyone just learning it. It can take some time to understand the ins and outs of Magento and how everything works. You will rely a lot on Google to get help on different error messages and how to get a simple style change to reflect on the website. However, Magento also provides the ability to implement complicated features with a little less hassle, using the predefined classes, libraries, and utility functions.</p><p>Development in Prestashop is a little less organized. If you look at different modules, you’ll find that some elements in the development do not have a set convention. I worked on Prestashop after working on Magento, and I found Prestashop a little premature in this matter. However, development in Prestashop is much faster than Magento which is a very important factor as well. It is also easier for beginner developers.</p><p><strong>Who wins: </strong>Prestashop for easiness and speed, Magento for better implementation and organization of modules and functionalities.</p><hr><h3 id="conclusion">Conclusion</h3><p>So after this detailed analysis, the conclusion is this:</p><ol><li>If the business you’re working on/for requires complicated features and business conditions, go with Magento.</li><li>If the business needs something simple and straightforward, go with Prestashop.</li><li>If you’re in between, look at the “Who wins” section in each of the discussed points above and decide what’s more important to you or your client.</li></ol><p>Did this article help you decide what you will use? Or do you have any more questions about Magento or Prestashop? Let me know down below!</p></hr></hr>]]></content:encoded></item><item><title><![CDATA[How I Learned About Contributing to Open Source Projects By Creating One]]></title><description><![CDATA[Every beginner can agree that your first contribution is very scary. This is how I learned to contribute to open source projects by creating one.]]></description><link>https://blog.shahednasser.com/how-i-learned-about-contributing-to-open-source-projects-by-creating-one/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e74</guid><category><![CDATA[Hacktoberfest]]></category><category><![CDATA[My Experience]]></category><category><![CDATA[Tips]]></category><category><![CDATA[Projects]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 12 Nov 2020 10:54:17 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/cb44950c4ed892aa5bdb959335cb60aa/photo-1579389083046-e3df9c2b3325.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/cb44950c4ed892aa5bdb959335cb60aa/photo-1579389083046-e3df9c2b3325.jpg" alt="How I Learned About Contributing to Open Source Projects By Creating One"/><p><em>This article was mentioned on Digital Ocean's <a href="https://www.digitalocean.com/blog/hacktoberfest-recap2020">Hacktoberfest Recap</a>.</em></p><p>Every beginner, whether to programming or to Open Source Projects, can agree that your first contribution is very scary. Not only do you not know how it works, but also you're scared of what response you will get when you send that first PR.</p><p>A lot of projects on GitHub aim to make first time contributors less scared of this. For example, the repository <a href="https://github.com/firstcontributions/first-contributions">First Contributions</a> aim to help you make that first contribution you are so scared of by making a simple change to the repository and guiding you in details on how to submit the PR. This is great and really helpful, but when you go to make a contribution to a repository that requires more real work, you still find it a little hard to contribute to it.</p><p>I personally had a trouble with it. I'm not a beginner developer, but I am a beginner to Open Source and trying those "repositories for first timers" were helpful in taking that first step, but I still found it difficult to contribute to bigger repositories. This was a hindrance for me as I really wanted to be a part of the Open Source community and collaborating with other contributors.</p><p>Then one day, I decided to create a repository that was so simple. The idea was just creating a library of pure CSS buttons that can be used in any website. I admit it's not an innovative idea, but it was a way to help me start with open source projects. The repository I created is <a href="https://github.com/sButtons/sbuttons"><strong>sButtons</strong></a>.</p><p>The website in the beginning was very simple and had almost nothing. It just had at most 15 buttons, a minimalist sidebar, and a text for a logo. It didn't even have a header or a footer, and the buttons were not that special, to be frank.</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/94340611-6dc3aa00-002d-11eb-8658-1e7a005e34d2.gif" class="kg-image" alt="How I Learned About Contributing to Open Source Projects By Creating One" loading="lazy"/></figure><p>Then I started posting issues to get help on making the library and the website that showcases it better. I posted issues about adding new buttons, improving the design and look and feel of the sidebar and navigation bar, adding a header and a footer, and even creating a logo, among other issues. At first I expected no one to care, as it was a small repository and maybe not that interesting, but I was overwhelmed by the comments and helps I received! People wanted to contribute to this open source project even though it had nothing in it.</p><p>Since I am a beginner to open source, I decided that this repository would mainly be focused on other beginner contributors. The main values to this repository would be:</p><ol><li>Try to always add simple issues that any beginner can take, and make sure no one other than beginners work on it.</li><li>When reviewing PRs or replying to other, make sure to never make beginners feel bad for their questions. Guide them through everything in steps, and be patient.</li><li>Be welcoming of everyone.</li></ol><p>And the number of contributors grew to maybe 60 which was a big deal to me! And then <a href="https://hacktoberfest.digitalocean.com/">Hacktoberfest</a> started, and for those of you who don't know, it's an annual event for developers that encourage contributing to open source projects by offering swag as a prize for your contributions. Developers all around the world participate and it is a big event for everyone.</p><p>I've never been a maintainer through Hacktoberfest. This was my first time, and as October started (which is the month Hacktoberfest happens in), I was overwhelmed by the contributors that wanted to contribute to the repository to participate in Hacktoberfest. I got into a point where I couldn't keep up with all the notifications, the issues and comments and PRs, so I created an organization, transferred the repository to it and added amazing members that still help massively in responding and reviewing and guiding beginner contributors. Without these members, my repository would still be in stage one.</p><p>Long story short, now (at the time of posting this) the repository has 113 stars and 420 forks, <a href="https://github.com/sButtons/sbuttons/blob/master/CONTRIBUTORS.md">180 contributors</a>, an <a href="https://www.npmjs.com/package/sbuttons">NPM package</a>, and <a href="https://sbuttons.github.io/sbuttons/">an awesome new renovated website.</a></p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/Screenshot-from-2020-11-12-11-26-20.png" class="kg-image" alt="How I Learned About Contributing to Open Source Projects By Creating One" loading="lazy"/></figure><p>We still have a long way to go, but I am very proud of what we have accomplished as we are all beginners and we are aspiring to help other beginners. </p><p>Through creating this project and repository, it helped me learn more about contributing to open source and collaborating with developers all over the world. Through helping others it helped me learn new things, and I think that's the beauty and purpose of open source projects. <strong>Helping and being part of the community.</strong></p><blockquote>The beauty and purpose of open source projects is helping and being part of the community.</blockquote><p>If you are new to open source projects as well or you would like to be a contributor to our repository, we have many issues waiting for you! Please check them out and start contributing <a href="https://github.com/sButtons/sbuttons/issues">here</a>!</p><p>In the end, I would like to mention all the members of the organization who have been a great help for me and who have taught me many things as well. They are (in no particular order):</p><ol><li><a href="https://github.com/glebkema">Gleb Kemarsky</a></li><li><a href="https://github.com/isonnymichael">Sonny Michael</a></li><li><a href="https://github.com/chaitanya4vedi">Chaitanya Chaturvedi</a></li><li><a href="https://github.com/Caleb335">Seven</a></li><li><a href="https://github.com/HADES-01">Aditya Vats</a></li><li><a href="https://github.com/dsnehasish74">Snehasish Dhar</a></li><li><a href="https://github.com/SARVESHKHANDELWAL">SARVESHKHANDELWAL</a></li><li><a href="https://github.com/TomWBush">Tom Wang</a></li></ol><p>Thank you all and thank you to every contributors that contributed to our project!</p>]]></content:encoded></item><item><title><![CDATA[Linux Tips for Beginners]]></title><description><![CDATA[Many beginners find it hard to understand and adapt to Linux. In this post I will list a few helpful tips for Linux that can help you use it efficiently.]]></description><link>https://blog.shahednasser.com/linux-tips-for-beginners/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e73</guid><category><![CDATA[Beginners]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 10 Nov 2020 09:52:57 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/cef95e4bbc4d4bc01a82516a264f8fe1/photo-1518432031352-d6fc5c10da5a.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/cef95e4bbc4d4bc01a82516a264f8fe1/photo-1518432031352-d6fc5c10da5a.jpg" alt="Linux Tips for Beginners"/><p>Many beginners find it hard to understand and adapt to Linux. In this post I will list a few helpful tips for Linux that can get you started on how to use it efficiently.</p><hr><h2 id="terminal-auto-completion">Terminal Auto Completion</h2><p>This is probably an easy, obvious one to many of us but it is still important to list. When using the terminal, you can use auto completion for commands or to use a file/folder in the directory you're currently in by pressing the <code class="language-text">TAB</code> key on your keyboard. This is helpful if you're still new to linux, if you just forgot what the name of the command is, or if you're just too lazy to type it out (like many of us are).</p><hr><h2 id="quick-navigation-between-directories">Quick Navigation Between Directories</h2><p>As you know in Linux, to move from one directory to the other in the terminal you use the <code class="language-text">cd</code> command. For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token builtin class-name">cd</span> my-folder</code></pre></div><p>There are three shortcuts that can help you navigate between directories:</p><ol><li><strong>Navigate to the Home directory</strong>: To move to the home directory, you just need to use <code class="language-text">cd ~</code>.</li><li><strong>Navigate to the parent directory: </strong>To move to the parent directory, you just need to use <code class="language-text">cd ..</code></li><li><strong>Navigate to the previous directory: </strong>To move to the directory you were previously in, you just need to use <code class="language-text">cd -</code></li></ol><hr><h2 id="moving-to-the-beginning-and-end-of-line">Moving To the Beginning and End of Line</h2><p>When you are running commands in the terminal, especially when you are copy/pasting the commands, a lot of time it can be a hassle when you want to edit something in the beginning of the line and then moving back to the end of it. There is an easier way to do it.</p><ol><li><strong>To move to the beginning of the line</strong> press <code class="language-text">CTRL + A</code></li><li><strong>To move to the end of the line </strong>press <code class="language-text">CTRL + E</code></li></ol><hr><h2 id="read-a-file-as-it-updates">Read a File As It Updates</h2><p>This is very essential when you are reading from a log file. To keep executing <code class="language-text">tail</code> every time you want to check for changes can be a hassle and frankly eye blinding.</p><p><em>In case you're not aware, tail is a command used to read the end of a file.</em></p><p>So to read a file and have it update as any new lines are added to the file, just add <code class="language-text">-f</code> option to the command. For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">tail</span> -f /var/logs/apache2/error.log</code></pre></div><p>This can be used on any file as well, not just logs.</p><hr><h2 id="reuse-the-previous-parameter">Reuse The Previous Parameter</h2><p>To use the parameter you've used in the previous command, use <code class="language-text">!$</code>. For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">touch</span> test.txt // creates a new <span class="token function">file</span> test.txt <span class="token function">nano</span> <span class="token operator">!</span>$ // edit the previous parameter <span class="token function">which</span> is test.txt</code></pre></div><hr><h2 id="reuse-the-previous-command">Reuse The Previous Command</h2><p>To reuse the previous command, use <code class="language-text">!!</code>. For example</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">tail</span> -n <span class="token number">100</span> error.log <span class="token operator">!</span><span class="token operator">!</span> //use the previous <span class="token builtin class-name">command</span> again</code></pre></div><p>This is mostly helpful when you run a command, but realize you need to add <code class="language-text">sudo</code> to it. So instead of going to the beginning of the line to do that, just use <code class="language-text">sudo !!</code></p><hr><h2 id="get-information-about-any-command">Get Information About Any Command</h2><p>If you want to get information about any command like its description of the options and parameters it accepts, simply add <code class="language-text">--help</code> to it. For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token builtin class-name">cd</span> --help</code></pre></div><hr><h2 id="copying-and-pasting-from-the-terminal">Copying and Pasting From The Terminal</h2><p>To copy anything from the terminal, use <code class="language-text">CTRL + SHIFT + C</code></p><p>To paste anything to the terminal, use <code class="language-text">CTRL + SHIFT + V</code></p><hr><h2 id="search-through-the-commands">Search Through The Commands</h2><p>If you've used a command and you want to use it again, but you forgot some of it or you're just too lazy to type it out, one way to use it again is by searching in your terminal. To do that, press <code class="language-text">CTRL + R</code> and then type in the command. As you type you will see commands that match your search and when you find what you need, press <code class="language-text">ENTER</code> and the command will run.</p><hr><h2 id="reading-files-in-parts">Reading Files in Parts</h2><p>Use <code class="language-text">less</code> to read a file a little by little. Many people use <code class="language-text">cat</code> but if the file is big then using <code class="language-text">cat</code> can be overwhelming. When you use <code class="language-text">less</code> you can go through the file in parts and at your own pace. Example of usage:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">less</span> test.txt</code></pre></div><p>To exit the file you are reading just type <code class="language-text">q</code>.</p><hr><h2 id="and-there-s-still-many-more-">And There's Still Many More!</h2><p>If you have any other linux tips that make your day less of a pain, please share them with everyone below!</p></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Web Design Tips For Web Developers]]></title><description><![CDATA[Some tips on Web Design for Web Developers I have learned from a FREE Udemy course that are essential for your websites.]]></description><link>https://blog.shahednasser.com/web-design-tips-for-web-developers/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e6e</guid><category><![CDATA[Design]]></category><category><![CDATA[Tips]]></category><category><![CDATA[Beginners]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 26 Oct 2020 21:41:21 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/6f6b73f2356f89c8be0c82d9fe78a145/photo-1542744094-3a31f272c490.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/6f6b73f2356f89c8be0c82d9fe78a145/photo-1542744094-3a31f272c490.jpg" alt="Web Design Tips For Web Developers"/><p>Recently I took a course on Udemy called <a href="https://www.udemy.com/web-design-secrets/learn/v4/overview" rel="noopener noreferrer">Web Design for Web Developers</a>. The course is very short and has a few simple tips that are actually really important to achieve a clean design for your website.</p><p>I advise you to take the course - it is only one hour long and it is <strong>FREE</strong> - to get a better understanding of these tips. However, I will be sharing with you what I learned in the hopes that it will help you out.</p><hr><h3 id="typography">Typography</h3><ul><li>Font size should be between 15px and 25px for body text.</li><li>Headlines should have a big font size</li><li>Line height should be between 120% and 150% of font size.</li><li>Pick a font that reflects the feel of the website, and stick with it for the entire website</li></ul><hr><h3 id="colors">Colors</h3><ul><li>Specify a base color</li><li>Using online tools, create a palette based on different shades of the base color or what colors go well with it.</li><li>For Call To Action buttons, use colors that will draw the attention of the user</li><li>Do not overuse Black in your design</li></ul><hr><h3 id="images">Images</h3><ul><li>When putting text over images, make sure to add an overlay to the image so the text can be readable.</li><li>If you do not want to add an overlay, you could put the text in a box and give it a background color.</li><li>Another option is to blur the image.</li></ul><hr><h3 id="icons">Icons</h3><ul><li>Use icons for features, services, steps, etc.</li><li>Make sure the icons are easily understood to not cause confusion, especially if they are not accompanied by text.</li><li>Label your icons.</li></ul><hr><h3 id="spacing-layout">Spacing/Layout</h3><ul><li>Put whitespace between website sections to make the start and end of a section apparent.</li><li>Base the layout on what you want your audience to focus on.</li><li>Make sure the whitespace between elements is not too small that everything looks crowded</li></ul><hr><h3 id="conclusion">Conclusion</h3><p>These are just a few of the helpful tips I learned from the course. To get more insight and understand the concepts more clearly, take an hour to go through the course.</p><!--kg-card-begin: html--><div class="suggested-read"><h4>Suggested Read</h4><p>Hiring managers looking to spot the best web developers may want <a href="https://www.toptal.com/web#hiring-guide" rel="noopener noreferrer" target="_blank">to check out this article</a> from Toptal. </p></div><!--kg-card-end: html--></hr></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Tips for Magento 2 Layouts]]></title><description><![CDATA[One of the things you will use a lot while developing in Magento 2 is the XML layouts, which can be confusing in the beginning.]]></description><link>https://blog.shahednasser.com/tips-for-magento-2-layouts/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e70</guid><category><![CDATA[Magento]]></category><category><![CDATA[Beginners]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sat, 08 Feb 2020 18:24:00 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/32e0e004999f20bd55bad508d863fad3/1_bwLgYgHn7R2RXs13d9HYfA.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/32e0e004999f20bd55bad508d863fad3/1_bwLgYgHn7R2RXs13d9HYfA.png" alt="Tips for Magento 2 Layouts"/><p>Magento 2 is one of the most popular e-commerce platforms, and it’s probably the most difficult to use for developers. One of the things you will use a lot while developing in Magento 2 is the XML layouts, which can be confusing in the beginning.</p><p>I will include some quick tips you might need in developing and modifying existing layouts.</p><h1 id="move-elements">Move Elements</h1><p>If you want to move a block or container from one place to another in a page, you can use the following: </p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>move</span> <span class="token attr-name">element</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>element.to.move<span class="token punctuation">"</span></span> <span class="token attr-name">destination</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>new.parent<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code></pre></div><p>Here, we have the <code class="language-text">element</code> attribute which should be the name of the block or container you want to move, and the <code class="language-text">destination</code> attribute which should be the name of the block or container you want to move the element to.</p><p>You can also use <code class="language-text">before</code> or <code class="language-text">after</code> attributes to specify where the element should go inside the parent like this:<move element="element.to.move" destination="new.parent" after="<strong><strong>new.sibling</strong></strong>" /></p><p>where <code class="language-text">new.sibling</code> is another child in <code class="language-text">new.parent</code></p><h1 id="remove-element">Remove Element</h1><p>To remove a block from a page, use the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>referenceBlock</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>element.to.remove<span class="token punctuation">"</span></span> <span class="token attr-name">remove</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code></pre></div><p>You can also do the same for containers:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>referenceContainer</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>element.to.remove<span class="token punctuation">"</span></span> <span class="token attr-name">remove</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code></pre></div><p><strong><strong>Note</strong></strong>: When Magento applies layout changes, <code class="language-text">move</code> rules are applied before <code class="language-text">remove</code> . This means if you move an element to a parent, and remove then the parent, the element you moved into it will be removed as well.</p><h1 id="change-a-block-s-template">Change a Block’s Template</h1><p>To change a block’s template, you can do the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>referenceBlock</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>block.to.change<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>action</span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>setTemplate<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>argument</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>template<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xsi:</span>type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>string<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>VENDOR_MODULE::path/to/template<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>argument</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>action</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>referenceBlock</span><span class="token punctuation">></span></span></code></pre></div><p>Where <code class="language-text">VENDOR_MODULE::path/to/template</code> should be the path to the new template you want to use for the block.</p><h1 id="change-block-s-visibility-based-on-configuration">Change Block’s Visibility Based on Configuration</h1><p>If you want a block to be visible based on configuration’s value that is set by the admin, you can do it this way:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>block</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>...<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>...<span class="token punctuation">"</span></span> <span class="token attr-name">ifconfig</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>my/yesno/field<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code></pre></div><p>Where <code class="language-text">my/yesno/field</code> can be any path to a field in the system settings.</p><h1 id="remove-css-or-js-files">Remove CSS or JS files</h1><p>To remove a css, javascript or any static file present in <code class="language-text"><head></code> , use the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>remove</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>src/to/file<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span></code></pre></div><h1 id="set-attributes-of-body">Set Attributes of Body</h1><p>To set attributes of the body of a page, like class, use the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="xml"><pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>attribute</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>class<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>class-name<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span></code></pre></div><p>You can also set <code class="language-text">style</code> , <code class="language-text">class</code> and other attributes.</p><h1 id="conclusion">Conclusion</h1><p>Those were just some quick tips you will probably use a lot if you’re developing a store with Magento 2. You can read more about this, as well as other helpful information, see <a href="https://devdocs.magento.com/guides/v2.3/frontend-dev-guide/layouts/xml-manage.html" rel="noopener nofollow">here</a>.</p>]]></content:encoded></item><item><title><![CDATA[Quran In New Tab - Chrome Extension]]></title><description><![CDATA[Replace the new tab page with Quran verses and beautiful nature pictures. The verses and pictures are randomly generated hourly.]]></description><link>https://shahednasserblog.tk/quran-in-new-tab-chrome-extension</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e6f</guid><category><![CDATA[Projects]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Wed, 06 Nov 2019 18:23:00 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/34fbf15a86a81d576af29f787f7f9f04/quran.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: html--><ul class="actions special"> <li><a href="https://chrome.google.com/webstore/detail/quran-in-new-tab/hggkcijghhpkdjeokpfgbhnpecliiijg?hl=en" class="button large">Download Now</a></li> </ul><!--kg-card-end: html--><img src="https://blog.shahednasser.com/static/34fbf15a86a81d576af29f787f7f9f04/quran.jpg" alt="Quran In New Tab - Chrome Extension"/><p>Replace the new tab page with Quran verses and beautiful nature pictures. The verses and pictures are randomly generated hourly. You can choose to show or hide your top sites.</p><p><strong>NEW </strong>I am working on adding more languages to this extension, and I need help with many of them. If you think you can help in translating it, please go <a href="https://crowdin.com/project/quran-in-new-tab-extension">here</a> to start helping!</p><hr><h2 id="recitations">Recitations</h2><p>You can play an audio of the recitation of the verse shown. You can choose from the following reciters:</p><ul><li>Mashary Rashid Alafasy</li><li>Abdallah Basfar</li><li>Abdurrahmaan As-Sudais</li><li>Abdul Samad</li></ul><p>and many more.</p><hr><h2 id="translations">Translations</h2><p>You can turn on the translation for the verses. Some of the languages available for translations are:</p><ul><li>English</li><li>German</li><li>Spanish</li><li>Indonesian</li><li>Italian</li></ul><p>and many more.</p><hr><h2 id="athkar">Athkar</h2><p>Starting from version 1.0, you can show randomly generated Athkar on your new tab as well.</p><hr><h2 id="credits">Credits</h2><p>All Quran verses, audios and translations use the API of Al Quran Cloud<br>Icons from Feather<br>Logo from <a href="https://www.freeiconspng.com/img/8824">https://www.freeiconspng.com/img/8824</a><br/></br></br></p><hr><h2 id="issues">Issues</h2><p>If you find any issues or bugs, please create an issue on the <a href="https://github.com/shahednasser/quran-extension">Github Repo</a>.</p></hr></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[Best Websites to Find Free Resources for Frontend Web Developers and Designers]]></title><description><![CDATA[Perhaps one of the hardest tasks is finding free resources for your projects. This list will hold websites that offer freebies.]]></description><link>https://blog.shahednasser.com/best-websites-to-find-free-resources-for-frontend-web-developers-and-designers/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e6d</guid><category><![CDATA[Beginners]]></category><category><![CDATA[Tips]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[Design]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Mon, 26 Aug 2019 21:33:00 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/5b5b3cb18304a6e7b147980c13d0c5b3/photo-1505304451-3b3b85a91afe.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/5b5b3cb18304a6e7b147980c13d0c5b3/photo-1505304451-3b3b85a91afe.jpg" alt="Best Websites to Find Free Resources for Frontend Web Developers and Designers"/><p>Perhaps one of the hardest tasks is finding free resources for your projects. This list will hold websites that offer freebies. I will try to keep the list updated along the way.</p><p>Some of the websites may have a different license for each resource they offer, so you might need to look out for that.</p><hr><h2 id="general">General</h2><ol><li><a href="https://freebiesupply.com/" rel="noopener nofollow"><strong><strong>Freebie Supply</strong></strong></a><strong><strong>: </strong></strong>Free icons, vectors, fonts, templates, themes and more.</li><li><a href="https://freebiesbug.com/" rel="noopener nofollow"><strong><strong>Freebiesbug</strong></strong></a>: Another website that has a wide collection of icons, vectors, templates, and more.</li><li><a href="https://neede.co/" rel="noopener nofollow"><strong><strong>Neede</strong></strong></a><strong><strong>: </strong></strong>It’s aimed more towards designers, but developers might find some useful stuff like templates, colors, illustrations and more.</li></ol><h2 id="fonts">Fonts</h2><ol><li><a href="https://fonts.google.com/" rel="noopener nofollow"><strong><strong>Google Fonts</strong></strong></a></li><li><a href="https://www.1001fonts.com/" rel="noopener nofollow"><strong><strong>1001 Fonts</strong></strong></a></li></ol><h2 id="icons">Icons</h2><ol><li><a href="https://material.io/resources/icons/" rel="noopener nofollow"><strong><strong>Material Design Icons</strong></strong></a></li><li><a href="https://feathericons.com/" rel="noopener nofollow"><strong><strong>Feather</strong></strong></a></li><li><a href="https://www.svgrepo.com/" rel="noopener nofollow"><strong><strong>SVG Repo</strong></strong></a></li></ol><h2 id="website-templates">Website Templates</h2><ol><li><a href="https://www.free-css.com/" rel="noopener nofollow"><strong><strong>Free CSS</strong></strong></a>: Free CSS templates, layouts, and menus.</li><li><a href="https://www.freewebtemplates.com/" rel="noopener nofollow"><strong><strong>Free Web Templates</strong></strong></a></li><li><a href="https://freewebsitetemplates.com/" rel="noopener nofollow"><strong><strong>Free Website Templates</strong></strong></a></li><li><a href="https://onepagelove.com/templates/html-templates" rel="noopener nofollow"><strong><strong>One Page HTML templates</strong></strong></a></li><li><a href="https://bootstrapmade.com/" rel="noopener nofollow"><strong><strong>BootstrapMade</strong></strong></a>: Free website templates (requires attribution)</li><li><a href="https://html5up.net/" rel="noopener nofollow"><strong><strong>HTML5 UP!</strong></strong></a><strong><strong>: </strong></strong>Free responsive HTML5 templates (requires attribution)</li><li><a href="https://templated.co/" rel="noopener nofollow"><strong><strong>TEMPLATD</strong></strong></a>: Free HTML templates (requires attribution)</li></ol><h2 id="illustrations">Illustrations</h2><ol><li><a href="https://undraw.co/" rel="noopener nofollow"><strong><strong>unDraw</strong></strong></a>: Free illustrations for any project you can think of.</li><li><a href="https://lukaszadam.com/illustrations" rel="noopener nofollow"><strong><strong>Lukasz Adam’s Free Illustrations</strong></strong></a><strong><strong>: </strong></strong>Free unique illustrations.</li><li><a href="https://www.drawkit.io/" rel="noopener nofollow"><strong><strong>DrawKit</strong></strong></a>: Free wide range of illustrations.</li></ol><h2 id="images">Images</h2><ol><li><a href="https://unsplash.com/" rel="noopener nofollow"><strong><strong>Unsplash</strong></strong></a><strong><strong>: </strong></strong>Free images with no attribution required.</li><li><a href="https://www.pexels.com/" rel="noopener nofollow"><strong><strong>Pexels</strong></strong></a>: Free stock images with no attribution required.</li></ol><h2 id="gradients-and-colors">Gradients and Colors</h2><ol><li><a href="https://webgradients.com/" rel="noopener nofollow"><strong><strong>WebGradients</strong></strong></a>: Free gradients that you can either copy as CSS rules or download them as .sketch or .psd</li><li><a href="https://uigradients.com/#Pinky" rel="noopener nofollow"><strong><strong>uiGradients</strong></strong></a>: Free gradients that you can either copy as CSS rules or download them as .jpg images.</li><li><a href="https://gradienthunt.com/" rel="noopener nofollow"><strong><strong>Gradient Hunt</strong></strong></a>: Free gradients that you can either copy as CSS rules or download them as .png images. They also offer a Chrome extension.</li><li><a href="https://colorhunt.co/" rel="noopener nofollow"><strong><strong>Color Hunt</strong></strong></a>: Free color schemas. Also offers a Chrome extension.</li></ol><h2 id="other">Other</h2><ol><li><a href="https://www.patterncooler.com/" rel="noopener nofollow"><strong><strong>Pattern Cooler</strong></strong></a>: Free background patterns.</li><li><a href="http://thepatternlibrary.com/" rel="noopener nofollow"><strong><strong>The Pattern Library</strong></strong></a>: Free background patterns.</li><li><a href="https://hatchful.shopify.com/" rel="noopener nofollow"><strong><strong>hatchful</strong></strong></a>: Free logo generator.</li></ol></hr>]]></content:encoded></item><item><title><![CDATA[CSS Variables and How To Use Them]]></title><description><![CDATA[A lot of people don’t know about CSS variables, and you might be one of them! It’s time to learn about CSS variables and how you can use them.]]></description><link>https://blog.shahednasser.com/css-variables-and-how-to-use-them/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e6c</guid><category><![CDATA[CSS]]></category><category><![CDATA[Beginners]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sun, 21 Apr 2019 21:28:00 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/ffa580b4a342c60287433e8f82cb8e58/carbon--1-.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/ffa580b4a342c60287433e8f82cb8e58/carbon--1-.png" alt="CSS Variables and How To Use Them"/><p>A lot of people don’t know about CSS variables, and you might be one of them! It’s time to learn about CSS variables and how you can use them.</p><p>CSS variables are declared for a specific element as a custom property. Then, you can use that custom property anywhere you use that element.</p><hr><h1 id="declaration-and-usage">Declaration and Usage</h1><p>Here’s how you declare a custom property:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">element</span> <span class="token punctuation">{</span> <span class="token property">--background-color</span><span class="token punctuation">:</span> #f00<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Here, <code class="language-text">element</code> can be a selector of any element, for example, div, p, .test, etc…</p><p>What we did is that we declared a custom property for this element called <code class="language-text">--background-color</code> . All CSS custom properties must start with <code class="language-text">--</code> .</p><p>Now, we can use this custom property inside <code class="language-text">element</code> using the <code class="language-text">var</code> function.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">element</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--background-color<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Here, we assigned the background-color property of <code class="language-text">element</code> to the variable we declared earlier.</p><p>This is nice and all, but usually we have repetition inside different elements, not just one. declaring a custom variable inside one element type is not very convenient.</p><p>In order to use a custom property inside more than one element type, we can declare the custom property inside the <code class="language-text">:root</code> pseudo-class.</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span> <span class="token property">--primary-color</span><span class="token punctuation">:</span> #333<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Now, we can use the variable <code class="language-text">--primary-color</code> inside any element in our document:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">div</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--primary-color<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">p</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--primary-color<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.fancy</span> <span class="token punctuation">{</span> <span class="token property">border-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--primary-color<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>By declaring our custom property inside <code class="language-text">:root</code> , we are now able to use it inside <code class="language-text">div</code> to set the text color, <code class="language-text">p</code> to set the background color, and any element having class <code class="language-text">fancy</code> to set the border color. This way, not only did we minimize repetition, but we also made it easier to edit and change our website’s primary color at any given point.</p><hr><h1 id="inheritance">Inheritance</h1><p>Elements can also inherit custom properties. For example, let’s say we have the following HTML:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>parent<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>first-child<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>second-child<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre></div><p>Then, we declare a variable called <code class="language-text">--text-size</code> on <code class="language-text">.parent</code> :</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.parent</span> <span class="token punctuation">{</span> <span class="token property">--text-size</span><span class="token punctuation">:</span> 15px<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Now, we can use <code class="language-text">--text-size</code> not only inside <code class="language-text">.parent</code> , but also inside its children as well:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.first-child</span> <span class="token punctuation">{</span> <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text-size<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>We can also override custom properties. We can do that by redeclaring the custom property inside the child element:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.second-child</span> <span class="token punctuation">{</span> <span class="token property">--text-size</span><span class="token punctuation">:</span> 30px<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Now, if you use <code class="language-text">--text-size</code> inside <code class="language-text">.second-child</code> , it’ll be evaluated to 30px, but if you use it inside <code class="language-text">.first-child</code> or <code class="language-text">.parent</code>, it will still be 15px.</p><hr><h1 id="fallback-values">Fallback Values</h1><p>You can also define a fallback value for a variable by passing a second parameter to <code class="language-text">var</code> . For example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.second-child</span> <span class="token punctuation">{</span> <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text-size<span class="token punctuation">,</span> 30px<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>Fallback values are used when the variable is not defined yet. They are <strong><strong><em><em>not</em></em></strong></strong> used as a fallback to browser incompatibility.</p><hr><h1 id="conclusion">Conclusion</h1><p>And that’s how you can use CSS variables! Keep in mind that some browsers like Internet Explorer don’t support them, so if you need to support all browsers you need to take that into consideration.</p></hr></hr></hr></hr>]]></content:encoded></item><item><title><![CDATA[React Hooks Tutorial — Create a Number Trivia Generator Website]]></title><description><![CDATA[In this tutorial, you’ll learn how to exactly use hooks in React. We will build a simple website that generates number trivia.]]></description><link>https://blog.shahednasser.com/react-hooks-tutorial-create-a-number-trivia-generator-website/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e72</guid><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Tue, 16 Apr 2019 07:34:00 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/811e7e5724a90f775f8832f17c9353ff/1_-Ijet6kVJqGgul6adezDLQ.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/811e7e5724a90f775f8832f17c9353ff/1_-Ijet6kVJqGgul6adezDLQ.png" alt="React Hooks Tutorial — Create a Number Trivia Generator Website"/><p>Hooks have been officially added to React as of React 16.8. One of the main benefits of Hooks in React is that you can use state and effect (which is generally a combination of different life cycles into one) in a component without creating a class.</p><p>In this tutorial, you’ll learn how to exactly use hooks in React. We will build a simple website that gives the user some options to pick from in order to generate some random number trivia.</p><p>You can check out the demo for the website <a href="http://numbers-trivia.surge.sh/" rel="noopener nofollow">here</a>, and the source code on the <a href="https://github.com/shahednasser/numbers-trivia" rel="noopener nofollow">GitHub repository</a>.</p><p>Let’s first start by creating a react app. Since our website will be very simple, we will use the <code class="language-text">create-react-app</code> command. If you don’t have it installed, you can install it using <code class="language-text">npm</code><strong><strong>.</strong></strong></p><p>Run the following in your terminal or CMD:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> i -g create-react-app</code></pre></div><p>This will install <code class="language-text">create-react-app</code> globally.</p><p>Now we can create our React app:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">create-react-app numbers-trivia</code></pre></div><p>Running this command will create a directory in the working directory with the name you supply for the React app. I named it <strong><strong>numbers-trivia</strong></strong> but you can call it whatever you want.</p><p>Inside that directory, it will also install all the packages and files needed to run the website. It will install packages like <strong><strong>react</strong></strong>, <strong><strong>react-dom</strong></strong>, <strong><strong>react-scripts</strong></strong> and more.</p><p>Once it’s done, change into the newly created directory and start the server:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token builtin class-name">cd</span> numbers-trivia <span class="token function">npm</span> start</code></pre></div><p>Once you start the server, a web page of your website in your favorite browser will open. You will see a page with just the logo and a link to learn React.</p><p>Before we start changing the page, if you are not familiar with React, let’s take a look at the structure of our React app. It should look something like this:</p><figure class="kg-card kg-image-card"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/1_R1irPlPj9UsboCM_KI5CgA.png" class="kg-image" alt="React Hooks Tutorial — Create a Number Trivia Generator Website" loading="lazy"/></figure><p>In our root directory, we will find a bunch of directories. <strong><strong>node_modules </strong></strong>holds all the packages React needs to run and any package you might add. <strong><strong>public </strong></strong>holds the files our server serves.</p><p>The directory that we will spend most of our time in is the <strong><strong>src</strong></strong> directory. This directory will hold all of our React components.</p><p>As you can see there are a bunch of files in that directory. <strong><strong>index.js</strong></strong> is basically the file that renders our highest React component.</p><p>We only have one React component right now which is in <strong><strong>App.js. </strong></strong>If you open it, you will find the code that renders the logo with the link to learn React that you currently see on the website.</p><p>So, in order to see how changing our App component will change the content of the website, let’s modify the code by removing the current content and replacing it with our favorite phrase: “Hello, World!”</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> logo <span class="token keyword">from</span> <span class="token string">'./logo.svg'</span> <span class="token keyword">import</span> <span class="token string">'./App.css'</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"App"</span><span class="token operator">></span> <span class="token operator"><</span>header className<span class="token operator">=</span><span class="token string">"App-header"</span><span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span>Hello<span class="token punctuation">,</span> World<span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>header<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App</code></pre></div><p>We just replaced the content of the <strong><strong>header</strong></strong> element. Now, if your server is still running you will see that your page updated without you refreshing it, and you will see that the previous content is replaced with <strong><strong>Hello, World!</strong></strong></p><p>So now we know how and where we should edit our React components in order to get the result we want. We can go ahead and start with our objective.</p><p>What we’ll do for this website is the following:</p><ol><li>Show a welcome message the first time the user opens the website, then replace it with a message prompting the user to try the generator.</li><li>Render a form with <strong><strong>text </strong></strong>and <strong><strong>select</strong></strong> inputs. The <strong><strong>text </strong></strong>input is where the user can enter the number they want to see trivia about, and the <strong><strong>select </strong></strong>input will provide the user with options related to the trivia.</li><li>On submitting the form, send a request to <a href="http://numbersapi.com/" rel="noopener nofollow">this API</a> to fetch the trivia we need.</li><li>Render the trivia for the user to see it.</li></ol><p>Let’s start by organizing our directory structure first. In React it’s good practice to create a directory inside <strong><strong>src</strong></strong> holding all the components. We’ll create a directory called <strong><strong>components</strong></strong>. Once you create the directory, move <strong><strong>App.js</strong></strong> into there. We will also create a directory called <strong><strong>styles</strong></strong> and move <strong><strong>App.css </strong></strong>and <strong><strong>index.css </strong></strong>into it.</p><p>When you do that, you will need to change the imports in your files as following:</p><ol><li>in <strong><strong>index.js:</strong></strong></li></ol><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> ReactDOM <span class="token keyword">from</span> <span class="token string">'react-dom'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token string">'../styles/index.css'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> App <span class="token keyword">from</span> <span class="token string">'./components/App'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token keyword">as</span> serviceWorker <span class="token keyword">from</span> <span class="token string">'./serviceWorker'</span><span class="token punctuation">;</span></code></pre></div><p>2. in <strong><strong>App.js:</strong></strong></p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> logo <span class="token keyword">from</span> <span class="token string">'./logo.svg'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token string">'../styles/App.css'</span><span class="token punctuation">;</span></code></pre></div><p>Our directory structure should look like this now:</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/1_Aqgelb3qbhJiESUbGGNUoQ.png" class="kg-image" alt="React Hooks Tutorial — Create a Number Trivia Generator Website" loading="lazy"/></figure><p>We will go ahead now and start building our webpage.</p><p>The first thing in our objectives list is showing a welcome message when the user first opens the webpage. It will show up for 3 seconds, and then changes to another message that will prompt the user to try out the trivia generator.</p><p>Without hooks, this could be done by using React’s lifecycle method <code class="language-text">componentDidMount</code><em><em> </em></em>which runs right after the component first renders.</p><p>Now, we can use the <a href="https://reactjs.org/docs/hooks-effect.html" rel="noopener nofollow"><em><em>effect hook</em></em></a><em><em> </em></em>instead. It will look something like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">//perform something post render</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>The function you pass to <code class="language-text">useEffect</code> will be executed after every render. This combines the lifecycles methods <code class="language-text">componentDidMount</code><strong><strong> </strong></strong>and <code class="language-text">componentDidUpdate</code> into one.</p><p>What if you want to do something just after the first time the component renders, like in <code class="language-text">componentDidMount</code>? You can do this by passing a second parameter to <code class="language-text">useEffect</code>.</p><p><code class="language-text">useEffect</code><strong><strong> </strong></strong>accepts an array as a second parameter. This parameter is used as a condition on when to perform the passed function. So, let’s say you want to change a counter only after the variable <strong><strong>counter </strong></strong>changes, you can do it like so:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> document<span class="token punctuation">.</span>title <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">You have clicked </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>counter<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> times</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token punctuation">[</span>counter<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>This way, the function passed to <code class="language-text">useEffect</code> will run after render only if the value for <code class="language-text">counter</code><strong><strong> </strong></strong>changes.</p><p>If we want the function to run only after the first render, we can do that by passing an <strong><strong>empty</strong></strong> array as the second parameter.</p><p>Let’s come back now to what we want to do. We want to show a welcome message when the user first opens the page, then change that message after 3 seconds. We can do that by adding the following inside <strong><strong>App.js</strong></strong>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span>useEffect<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Form <span class="token keyword">from</span> <span class="token string">'./Form'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token string">'../styles/App.css'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">let</span> welcomeMessage <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"welcomeMessage"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> welcomeMessage<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token string">"Try Out Our Trivia Generator!"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"App"</span><span class="token operator">></span> <span class="token operator"><</span>header className<span class="token operator">=</span><span class="token string">"App-header"</span><span class="token operator">></span> <span class="token operator"><</span>h1 id<span class="token operator">=</span><span class="token string">"welcomeMessage"</span><span class="token operator">></span>Welcome to Numbers Trivia<span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>Form <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>header<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span></code></pre></div><p>Here’s what we’re doing:</p><ol><li><strong><strong>Line 1:</strong></strong> We added an import for <code class="language-text">useEffect</code></li><li><strong><strong>Line 4: </strong></strong>We changed our class component into a function component</li><li><strong><strong>Line 5–10: </strong></strong>we added an effect to our function component. This effect sets a timer after 3 seconds that will change the text in the element with the id <code class="language-text">welcomeMessage</code><strong><strong>. </strong></strong>Because we passed an <strong><strong>empty</strong></strong> array to <code class="language-text">useEffect</code>, this effect will only run once.</li><li><strong><strong>Line 11–17: </strong></strong>We replaced the previous code in <strong><strong>App.js </strong></strong>to render an <strong><strong>h1 </strong></strong>element having the id <code class="language-text">welcomeMessage</code><strong><strong>, </strong></strong>which is our target element.</li></ol><p>Okay, now go to our web page and see the changes. At first, the welcome message “<strong><strong>Welcome to Numbers Trivia!</strong></strong>” will show up, then 3 seconds later it will change into “<strong><strong>Try Out Our Trivia Generator!</strong></strong>” We just used a React Hook!</p><p>Next, let’s create our form input elements. To do that, we will create a new React component called <code class="language-text">Form</code><strong><strong>. </strong></strong>Create in the directory <strong><strong>components</strong></strong> the file <strong><strong>Form.js. </strong></strong>For now, it will just include the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Form</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Form<span class="token punctuation">;</span></code></pre></div><p>This will create the new React component. We’re just importing React, then we’re creating a function called Form. As we said earlier in the tutorial, with the use of hooks we can now create components as stateful functions rather than classes. And in the last line, we’re exporting <strong><strong>Form</strong></strong> in order to import it in other files.</p><p>In the form, we will have a <strong><strong>text </strong></strong>input and <strong><strong>select </strong></strong>elements. This is based on the API we’re using. In the API, two parameters can be sent:</p><ol><li><strong><strong>number: </strong></strong>the number you want to get the trivia for. It can be an <strong><strong>integer</strong></strong>, a date of the form <strong><strong>month/day, </strong></strong>or the keyword <strong><strong>random </strong></strong>which will retrieve facts about a random number.</li><li><strong><strong>type: </strong></strong>the type of information you want to get. There are a few types: <strong><strong>math, date, year, </strong></strong>or, the default, <strong><strong>trivia.</strong></strong></li></ol><p>We will consider the text input element as optional. If the user does not enter a number or a date, we will send the keyword <strong><strong>random</strong></strong> for the number element.</p><p>Let’s add the following code inside the <strong><strong>Form</strong></strong> function in order to render our form:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">Form</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token operator"><</span>form<span class="token operator">></span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"text"</span> name<span class="token operator">=</span><span class="token string">"number"</span> placeholder<span class="token operator">=</span><span class="token string">"Enter a number (Optional)"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>select name<span class="token operator">=</span><span class="token string">"type"</span><span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"trivia"</span><span class="token operator">></span>Trivia<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"math"</span><span class="token operator">></span>Math<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"date"</span><span class="token operator">></span>Date<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"year"</span><span class="token operator">></span>Year<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>select<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span>Generate<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>This will create the form with the <strong><strong>text </strong></strong>input and <strong><strong>select </strong></strong>and <strong><strong>button </strong></strong>elements.</p><p>After that, we need to import and render the <strong><strong>Form</strong></strong> component in our <strong><strong>App </strong></strong>component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span>useEffect<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Form <span class="token keyword">from</span> <span class="token string">'./Form'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token string">'../styles/App.css'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">let</span> welcomeMessage <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"welcomeMessage"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> welcomeMessage<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token string">"Try Out Our Trivia Generator!"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"App"</span><span class="token operator">></span> <span class="token operator"><</span>header className<span class="token operator">=</span><span class="token string">"App-header"</span><span class="token operator">></span> <span class="token operator"><</span>h1 id<span class="token operator">=</span><span class="token string">"welcomeMessage"</span><span class="token operator">></span>Welcome to Numbers Trivia<span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>Form <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>header<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span></code></pre></div><p>We have changed the imports to import our <code class="language-text">Form</code><strong><strong> </strong></strong>component, and we added <code class="language-text"><Form /></code><strong><strong> </strong></strong>to render the form.</p><p>Let’s also add more styles just to make our form look a little better. Add the following at the end of <strong><strong>App.css</strong></strong>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">form</span> <span class="token punctuation">{</span> <span class="token property">font-size</span><span class="token punctuation">:</span> 15px<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">form input, form select</span> <span class="token punctuation">{</span> <span class="token property">padding</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">form select</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">form div</span> <span class="token punctuation">{</span> <span class="token property">margin-bottom</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>If you refresh the page now, you will find it has changed and now it’s showing our form.</p><p>Now, we need to add some logic to our form. <strong><strong>On Submit</strong></strong>, we need to get the values of our input elements, then call the API to retrieve the results.</p><p>To handle form elements and their values, you need to use the state of the component. You make the value of the element equal to a property in the state of the component.</p><p>Before hooks, in order to get the value in the state you would have to use <code class="language-text">this.state.value</code><strong><strong>, </strong></strong>and then to set the state, you will need to call <code class="language-text">this.setState</code>.</p><p>Now, you can use the state hook. The state hook is the <code class="language-text">useState</code><strong><strong> </strong></strong>function. It accepts one argument, which is the initial value, and it returns a pair of values: the <strong><strong>current state</strong></strong> and a <strong><strong>function</strong></strong> that updates it. Then, you will be able to access the current state using the first returned value, and update it using the second returned value which is the function.</p><p>Here’s an example:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span> setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>in this example, we call the <code class="language-text">useState</code><strong><strong> </strong></strong>hook and pass it 0, and we set the returned value equal to <code class="language-text">count</code> and <code class="language-text">setCount</code>. This means that we have created state variable called <code class="language-text">count</code>. Its initial value is 0, and to change its value we can use <code class="language-text">setCount</code>.</p><p>For our <code class="language-text">Form</code><strong><strong> </strong></strong>component, we need two state variables, one for the text<strong><strong> </strong></strong>input which we will call <code class="language-text">number</code>, and one for the select<strong><strong> </strong></strong>input which we will call <code class="language-text">type</code>. Then, on change event for these two input elements, we will change the values for <code class="language-text">number</code><strong><strong> </strong></strong>and <code class="language-text">type</code> using the function returned by <code class="language-text">setState</code><strong><strong>.</strong></strong></p><p>Open our <code class="language-text">Form</code><strong><strong> </strong></strong>component and change it to the following:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Form</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">let</span> <span class="token punctuation">[</span>number<span class="token punctuation">,</span> setNumber<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">"random"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> <span class="token punctuation">[</span>type<span class="token punctuation">,</span> setType<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">"trivia"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">onNumberChanged</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">let</span> value <span class="token operator">=</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>value<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token function">setNumber</span><span class="token punctuation">(</span><span class="token string">"random"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//default value</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token function">setNumber</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">onTypeChanged</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">let</span> value <span class="token operator">=</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>value<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token function">setType</span><span class="token punctuation">(</span><span class="token string">"trivia"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//default value</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token function">setType</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token operator"><</span>form<span class="token operator">></span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"text"</span> name<span class="token operator">=</span><span class="token string">"number"</span> placeholder<span class="token operator">=</span><span class="token string">"Enter a number (Optional)"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>number<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span>onNumberChanged<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>select name<span class="token operator">=</span><span class="token string">"type"</span> value<span class="token operator">=</span><span class="token punctuation">{</span>type<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{</span>onTypeChanged<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"trivia"</span><span class="token operator">></span>Trivia<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"math"</span><span class="token operator">></span>Math<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"date"</span><span class="token operator">></span>Date<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"year"</span><span class="token operator">></span>Year<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>select<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span>Generate<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Form<span class="token punctuation">;</span></code></pre></div><ol><li><strong><strong>Line 1: </strong></strong>add an import for <code class="language-text">useState</code> hook.</li><li><strong><strong>Line 3–4: </strong></strong>create two state variables <code class="language-text">number</code> and <code class="language-text">type</code> using <code class="language-text">useState</code> . Here we pass <strong><strong>random </strong></strong>as the initial value for number, and <strong><strong>trivia </strong></strong>as initial value for type because they are the default values for the parameters in the API.</li><li><strong><strong>Line 5–10: </strong></strong>implement input change handler functions for both text and select inputs, where we change the value of the state variables using the functions returned by <code class="language-text">useState</code> . If the value is unset, we automatically change the values to the default value.</li><li><strong><strong>Line 13: </strong></strong>pass the <code class="language-text">onNumberChanged</code> function to <code class="language-text">onChange</code> event for text input.</li><li><strong><strong>Line 16: </strong></strong>pass the <code class="language-text">onTypeChanged</code> function to <code class="language-text">onChange</code> event for select input.</li></ol><p>In addition, let’s go back to our <code class="language-text">App</code> component to modify it and use states. Instead of modifying our welcome message by changing the <code class="language-text">innerHTML</code> of the element, we will use a state. Our App component should now be like this:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import React, {useEffect, useState} from 'react'; import Form from './Form'; import '../styles/App.css'; function App() { const [ welcomeMessage, setWelcomeMessage ] = useState( "Welcome to Numbers Trivia!", ); useEffect(() => { setTimeout(() => { setWelcomeMessage("Try Out Our Trivia Generator!"); }, 3000); }, []); return ( <div className="App"> <header className="App-header"> <h1>{welcomeMessage}</h1> </header> <Form/> </div> ); } export default App;</code></pre></div><p>Now, we are using <code class="language-text">useState</code> to declare and initialize our welcome message. It will return <code class="language-text">welcomeMessage</code> , our state variable, and <code class="language-text">setWelcomeMessage</code> , which we will use to change the value of <code class="language-text">welcomeMessage</code> after 3 seconds from “<strong><strong>Welcome to Numbers Trivia!</strong></strong>” to “<strong><strong>Try Out Our Trivia Generator!</strong></strong>”</p><p>What’s left now is to add a function to handle the form’s <code class="language-text">onSubmit</code> event. On submit, we will send a request to the API with our parameters, then display the result.</p><p>In order to perform the request, we need to install <a href="https://github.com/axios/axios" rel="noopener nofollow">axios</a>:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> i axios</code></pre></div><p>Then, require axios at the beginning of <strong><strong>Form.js:</strong></strong></p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> axios <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'axios'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div><p>Now, add the following function below <code class="language-text">onTypeChanged</code> in our <strong><strong>Form</strong></strong> component:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">onSubmit</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'http://numbersapi.com/'</span> <span class="token operator">+</span> number <span class="token operator">+</span> <span class="token string">'/'</span> <span class="token operator">+</span> type<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">let</span> elm <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'result'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> elm<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> response<span class="token punctuation">.</span>data<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"error"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//simple error handling</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div><p>We’re just performing a request to the API, passing the <code class="language-text">number</code> and <code class="language-text">type</code> then displaying the result in an element of id <code class="language-text">result</code> (which we will add in a minute). In case of an error, we’re just displaying it in the console just as a simple error handling.</p><p>Now, let’s add this function as the handler for the form <code class="language-text">onSubmit</code> event in the return statement in Form.js:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="jsx"><pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>form</span> <span class="token attr-name">onSubmit</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>onSubmit<span class="token punctuation">}</span></span><span class="token punctuation">></span></span></code></pre></div><p>The only thing left is to add the <code class="language-text">#result</code> element. We can add it in <strong><strong>App.js </strong></strong>before <code class="language-text"><Form /></code> :</p><div class="kg-card kg-code-card gatsby-highlight" data-language="jsx"><pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>result<span class="token punctuation">"</span></span> <span class="token attr-name">style</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token literal-property property">marginBottom</span><span class="token operator">:</span> <span class="token string">'15px'</span><span class="token punctuation">}</span><span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre></div><p>Alright, now go to your website and discover all new trivia about numbers!</p><hr><h2 id="conclusion">Conclusion</h2><p>You just created a React app and used some React Hooks! Of course, there’s still more to explore and learn, so be sure to head to the <a href="https://reactjs.org/docs/hooks-intro.html" rel="noopener nofollow">docs</a> to learn more about React Hooks.</p></hr>]]></content:encoded></item><item><title><![CDATA[Chrome Extension Tutorial — Replace Images in Any Website with Pikachu]]></title><description><![CDATA[What’s a better way to learn how to make a Chrome extension than making the web cuter with Pikachu images?]]></description><link>https://blog.shahednasser.com/chrome-extension-tutorial-replace-images-in-any-website-with-pikachu/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e71</guid><category><![CDATA[Browser Extensions]]></category><category><![CDATA[Beginners]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Thu, 11 Apr 2019 18:30:00 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/498b0f8235a6b5cc5d72fd2244922304/chrome-extension.gif" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/498b0f8235a6b5cc5d72fd2244922304/chrome-extension.gif" alt="Chrome Extension Tutorial — Replace Images in Any Website with Pikachu"/><p><em>This article was also published on <a href="https://levelup.gitconnected.com/chrome-extension-tutorial-replace-images-in-any-website-with-pikachu-de2a6e3548bb">Level Up Coding's gitconnected</a></em></p><p>What’s a better way to learn how to make a Chrome extension than making the web cuter with Pikachu images?</p><p>In this tutorial, I will show you how you can create a simple Chrome extension that replaces images on websites with Pikachu images. We will discuss topics like content scripts, background scripts, and messages between scripts in Chrome extensions.</p><p>The code for this tutorial is available <a href="https://github.com/shahednasser/pikachu-everywhere" rel="noopener">here</a>.</p><p>First thing you need to do when creating any chrome extension is start with creating a <strong><strong>manifest.json </strong></strong>file in the root of the extension’s directory. For now, this file will hold only the following basic information about your extension:</p><!--kg-card-begin: html--><script src="https://gist.github.com/shahednasser/6beec3aa60a2187e99e85479f8806c30.js"/><!--kg-card-end: html--><p>Here is what everything in this file means:</p><ol><li><strong><strong>name:</strong></strong> The name of the extension. I named the extension “Pikachu Everywhere”</li><li><strong><strong>version</strong></strong>: This is the version of the extension. When you publish the extension in the Chrome Web Store and you need to update it, you will have to increase the version number so it’s good to start with a low number.</li><li><strong><strong>description: (Optional) </strong></strong>Description of your extension</li><li><strong><strong>manifest_version</strong></strong>: As of Chrome 18, developers are required to use manifest version 2, since manifest version 1 is now deprecated.</li><li><strong><strong>icons: (Optional) </strong></strong>Here we specify the extension’s icon. This icon will show up in your browser’s toolbar, the Chrome Web Store, and any other place that requires to show it. For that reason, it’s good to include different sizes of the icon. I have used an icon from <a href="https://www.freeiconspng.com/img/17360" rel="noopener">Free Icons PNG</a> and resized the icons using <a href="https://resizeimage.net/" rel="noopener">https://resizeimage.net/</a> (You can find the images in the <a href="https://github.com/shahednasser/pikachu-everywhere" rel="noopener">GitHub repository</a>). The paths specified for these images is relative to the root of the extension.</li></ol><p>With this, we have the core of any Chrome extension. Next, we’ll add the extension to the browser.</p><p>Go to chrome://extensions. There, you can toggle developer mode at the top right corner. Once you do that, a new toolbar will show up with three buttons: “Load unpacked,” “Pack extension,” and “Update.” Click on “Load unpacked” and choose your extension’s directory.</p><p>Once you do that, you will see that your new chrome extension is now working. Yes, it does nothing, but it’s working.</p><p>In Chrome extensions, there are two types of scripts you can use. There are Background scripts and Content scripts. Background scripts run (obviously) in the background. They are loaded when needed and unloaded when idle. They are used to listen to certain events in your Chrome extension.</p><p>Content scripts are scripts loaded once you open a website and injected it into it. Once you open a website, they will start running just like any other script on that website. After you close the website, the content scripts on that website will stop running as well.</p><p>For our extension, we want to replace every image on every website with Pikachu images. In order to do that we need to specify a content script that works every time you open a web page.</p><p>Let’s create our content script in <code class="language-text">assets/js/contentScript.js</code> and include the following script to test whether our extension is working or not:</p><!--kg-card-begin: html--><script src="https://gist.github.com/shahednasser/342ba17b0b6d715adaafd334a14416f9.js"/><!--kg-card-end: html--><p>One other thing we need to do is tell Chrome which script do we need to run as a content script. Add the following lines to <strong><strong>manifest.json</strong></strong></p><figure class="kg-card kg-embed-card"><iframe src="https://levelup.gitconnected.com/media/d35d7df4566f532c2a0948ea540ee302" allowfullscreen="" frameborder="0" height="0" width="0" title="adding content script to manifest.json" class="t u v hm aj" scrolling="auto" style="box-sizing: inherit; position: absolute; top: 0px; left: 0px; width: 680px; height: 0px;"/></figure><p>Here we are using <code class="language-text">content_scripts</code> as key with the value as an array. Here’s what everything in the array means:</p><ol><li><strong><strong>matches</strong></strong>: here you can specify which URLs the content script should run on. In our case we want our content script to run on all pages. So, we use the placeholder “<all_urls>” to specify that.</li><li><strong><strong>all_frames</strong></strong>: this key is used to allow the extension to specify if JavaScript and CSS files should be injected into all frames matching the specified URL requirements or only into the topmost frame in a tab.</li><li><strong><strong>js: </strong></strong>here we specify the script we want to run as a content script. You can specify more than one script, so the value has to be an array</li></ol><p>Now we’re ready to test our content script.</p><p>But before we do that we need to do one small step. In order to inform chrome that we updated our chrome extension, we need to go back to chrome://extensions, go to our extension, and press the reload icon.</p><p>To test if our content script is working, go to any web page you want, reload the page if it was opened before, then right-click and press Inspect. In DevTools, open the Console tab. You will see in your console as expected:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/chrome-extension-screenshot-1.png" class="kg-image" alt="Chrome Extension Tutorial — Replace Images in Any Website with Pikachu" loading="lazy"><figcaption>Console of a web page</figcaption></img></figure><p>So, we can verify that our content script is working. Try reloading the page, and the content script will execute again. Try opening another web page, and the content script will execute on that page independently.</p><p>Now, we know how to inject a script on any web page, and through that script we can do our work.</p><p>In our case, we need to replace every image in any website with random Pikachu images. To do that, we will use <a href="https://some-random-api.ml/img/pikachu" rel="noopener">this API</a> which will provide us with a JSON object containing the link of a Pikachu image. Each request to that API will look something like this:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/chrome-extension-screenshot-2.png" class="kg-image" alt="Chrome Extension Tutorial — Replace Images in Any Website with Pikachu" loading="lazy"><figcaption>Result of API call</figcaption></img></figure><p>With the help of this API, the steps to achieve what we need will be as follows:</p><ol><li>Get all image elements on the web page.</li><li>Perform a GET request to the API to retrieve a random Pikachu image link.</li><li>Replace the image elements’ <code class="language-text">src</code> attributes with the links we retrieve.</li></ol><p>This all sounds good and easy, but there is one complication: content scripts in Chrome extensions cannot perform Cross-Origin requests.</p><p>So how can we fetch the image URLs from the API? We will need to use a Background script.</p><p>As we specified earlier, Background scripts run in the background in Chrome. They are not dependent on any web page.</p><p>Scripts in Chrome extensions are isolated from each other. However, they share a mean of communication through the <a href="https://developer.chrome.com/extensions/api_index" rel="noopener">Chrome API</a>.</p><p>What we will do is that we will listen for a message in the <strong><strong>background</strong></strong> script sent from <strong><strong>content</strong></strong> scripts. Every time a web page opens, our content script will run, send a message to the background script requesting an image URL. The background script will then perform the asynchronous call to the Pikachu API, retrieve the link and send it back to the content script.</p><p>This may sound complicated at first, but it’s actually done in a very simple manner.</p><p>Let us first start by creating the background script and see it in action. Create <code class="language-text">assets/js/background.js</code> with the following content:</p><!--kg-card-begin: html--><script src="https://gist.github.com/shahednasser/b45de97a11eda346d1ea427b88c406f4.js"/><!--kg-card-end: html--><p>Now, we need to tell Chrome that the file we just created will be our background script. In order to do that, we need to go back to our <strong><strong>manifest.json</strong></strong> and add the following:</p><!--kg-card-begin: html--><script src="https://gist.github.com/shahednasser/c7a26cf5b3b2415110cb97e44f2b3834.js"/><!--kg-card-end: html--><p>Here is what everything means:</p><ol><li><strong><strong>scripts: </strong></strong>An array that holds the paths of the scripts we will use as background scripts. In our case, it’s just one.</li><li><strong><strong>persistent</strong></strong>: should always be false unless the extension uses Chrome’s Web Request API to block or modify network requests.</li></ol><p>Now, Chrome will know about our background script. It will load it when it’s needed, and unload it when it becomes idle.</p><p>To test our background script, we need to reload our extension as we did earlier.</p><p>Once you do that, you will see a new link appear in your extension’s info box with the text “inspect views background page”:</p><figure class="kg-card kg-image-card"><img src="https://res-5.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/chrome-extension-screenshot-3.png" class="kg-image" alt="Chrome Extension Tutorial — Replace Images in Any Website with Pikachu" loading="lazy"/></figure><p>If you click on it, a new DevTool will open and in the console you will see:</p><figure class="kg-card kg-image-card"><img src="https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/chrome-extension-screenshot-4.png" class="kg-image" alt="Chrome Extension Tutorial — Replace Images in Any Website with Pikachu" loading="lazy"/></figure><p>We can now confirm that our background script is working. Even if you close any other web page or reload any web page, nothing will change in the background script.</p><p>Let’s go back to our objective again. We now need to listen to messages in our background script, and on receiving a new message fetch the URL from the Pikachu API.</p><p>In order to listen to messages, we will use the following method in Chrome’s API:</p><!--kg-card-begin: html--><script src="https://gist.github.com/shahednasser/4426ca477880552e4c563be8264b968c.js"/><!--kg-card-end: html--><p>We need to pass a function to <code class="language-text">addListener</code>. This function will be executed on receiving any new message. The function takes three parameters:</p><ol><li><strong><strong>message: </strong></strong>the message sent of type any.</li><li><strong><strong>sender: </strong></strong>of type <a href="https://developer.chrome.com/extensions/runtime#type-MessageSender" rel="noopener">MessageSender</a></li><li><strong><strong>senderResponse: </strong></strong>Callback function to call (at most once) when you have a response. This function is sent by the sender on sending the message.</li></ol><p>So this is what our <strong><strong>background.js </strong></strong>file should look like now:</p><!--kg-card-begin: html--><script src="https://gist.github.com/shahednasser/4920b314274d2695b5ac0e771a4cd52c.js"/><!--kg-card-end: html--><p>Now our background script is ready to receive messages, but there are no messages being sent.</p><p>As we said earlier, each time a page opens, our content script will loop through image elements in the web page, and send a message to the background script to fetch the Pikachu image link.</p><p>In order to send messages, we will need to use the following method from Chrome’s API:</p><!--kg-card-begin: html--><script src="https://gist.github.com/shahednasser/03e371015982ef271518922e56139c19.js"/><!--kg-card-end: html--><p>The parameter’s being sent are as follows:</p><ol><li><strong><strong>extensionId: (Optional) </strong></strong>the ID of the extension we are sending the message to. If it’s omitted, the message will be sent to our own extension.</li><li><strong><strong>message:</strong></strong> The message we are sending of type any.</li><li><strong><strong>options: Optional</strong></strong></li><li><strong><strong>responseCallback: </strong></strong>The function to call after receiving the message. This is the <strong><strong>senderResponse</strong></strong> parameter in the previous method we saw.</li></ol><p>So, we will use this method in our content script to send a message to the background script to fetch the Pikachu URL from the API. Our content script should now look like this:</p><!--kg-card-begin: html--><script src="https://gist.github.com/shahednasser/bd4051325006a5f3ca01e882b51eebc5.js"/><!--kg-card-end: html--><p>Here’s what we’re doing in the above code:</p><ol><li><strong><strong>Line 1: </strong></strong>get all image elements on the web page.</li><li><strong><strong>Line 2–6: </strong></strong>Loop through the image elements. On each element, we send a message to the background script. As you can tell, we are omitting the optional <strong><strong>extensionId </strong></strong>and <strong><strong>options</strong></strong> parameters. The first parameter is the <strong><strong>message </strong></strong>we are sending, and the second parameter is the callback function we want the background to execute after it fetches the image’s link.</li></ol><p>We are sending the object <strong><strong>{msg: ‘image’, index: i}</strong></strong> to our extension. This object has two properties. The first one is to specify what our message is about. In our extension, it might not be very helpful, but when you have an extension that uses different types of messages, it’s a good idea to differentiate what each message is for. The second property is to specify the index of the image the link is for in the <strong><strong>images</strong></strong> array. The reason behind this is that the callback function replacing the image will be called asynchronously, so <strong><strong>i </strong></strong>might point at another index at the time it’s being executed.</p><p>The callback function receives an object that has two properties. <strong><strong>data</strong></strong> will be the data received from the API call, and <strong><strong>index</strong></strong> will be the index of the image in the array <strong><strong>images</strong></strong>. Once it’s called, it will set the image at <strong><strong>index</strong></strong> in <strong><strong>images</strong></strong> to the link property is <strong><strong>data</strong></strong>.</p><p>Now, we need to fetch the data from the API in our background script whenever the content script sends a message. We can do this as follows:</p><!--kg-card-begin: html--><script src="https://gist.github.com/shahednasser/9c024a8b40396e7c6a6ae1250fb5d94d.js"/><!--kg-card-end: html--><p>Here’s what’s going on here:</p><ol><li><strong><strong>Line 1:</strong></strong> Listen to messages in our extension</li><li><strong><strong>Line 2: </strong></strong>Check if the message is to get the image URL. This will use the <strong><strong>msg </strong></strong>attribute we passed when we sent the message in <strong><strong>contentScript</strong></strong></li><li><strong><strong>Line 3–8:</strong></strong> If the condition in <strong><strong>Line 2</strong></strong> is true, fetch the data from the API. In the first <code class="language-text">Promise</code> we get the response text, then in the second <code class="language-text">Promise</code> we parse the JSON object and call <strong><strong>senderResponse</strong></strong> which is the callback function specified by the sender of the message. We pass with it an object with the parameters <strong><strong>data </strong></strong>(the data received through the API call) and <strong><strong>index</strong></strong> (the index of the image, sent by the sender).</li><li><strong><strong>Line 9: </strong></strong>simple handling of any error that might occur.</li><li><strong><strong>Line 10</strong></strong>: If the sender specifies a callback function, it has to be called before the listener stops executing or else it will throw an error. In our case, we have to wait until we receive a response from the API which will happen asynchronously, so we return true to specify that it will be called asynchronously.</li></ol><p>Okay, our scripts are ready. Only one thing left — we need to give permission to the API in our <strong><strong>manifest.json:</strong></strong></p><!--kg-card-begin: html--><script src="https://gist.github.com/shahednasser/8d6786f1583a91fe31635715caf44b0c.js"/><!--kg-card-end: html--><p>All you need to do now is reload the extension in chrome://extensions, then open any page and see Pikachu everywhere!</p><p>Of course, this extension will not replace background images. This can be done by looping through elements, checking if they have background images, and replacing them the same way.</p>]]></content:encoded></item><item><title><![CDATA[Website Ideas To Practice Your Web Development Skills]]></title><description><![CDATA[It can be hard to practice your skills as a programmer, especially when you’re a beginner.]]></description><link>https://blog.shahednasser.com/website-ideas-to-practice-your-web-development-skills/</link><guid isPermaLink="false">Ghost__Post__6127ba1b3ed159214d382e6b</guid><category><![CDATA[Beginners]]></category><category><![CDATA[Tips]]></category><dc:creator><![CDATA[Shahed Nasser]]></dc:creator><pubDate>Sun, 10 Jun 2018 21:22:00 GMT</pubDate><media:content url="https://blog.shahednasser.com/static/6c6fc55bcf24f1e3efdaa0001ab5758e/photo-1517694712202-14dd9538aa97.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.shahednasser.com/static/6c6fc55bcf24f1e3efdaa0001ab5758e/photo-1517694712202-14dd9538aa97.jpg" alt="Website Ideas To Practice Your Web Development Skills"/><p>It can be hard to practice your skills as a programmer, especially when you’re a beginner. There are many websites that offer you exercises, easy or hard, to practice your skills and improve yourself.</p><p>However, the best way to improve your knowledge in programming languages is through practices that resemble real-life projects. Through these kinds of projects, you can basically get your hands dirty and benefit greatly for future real projects and any problems you might face then.</p><hr><p>I present to you today a few ideas for projects that can help you test your knowledge and expand it. These projects have the elements that can be a part of most websites.</p><p>Below you will find the ideas explained briefly with a few pointers on what features you can include. You can include as many features as you want or change the ideas to whatever you desire. I’m just giving you a place to start.</p><p><strong><strong>NOTE: These website ideas are for beginners whose skills are basic in HTML/CSS/Javascript/PHP. They are ordered from easiest to the more challenging ones. If you are looking to advance your skills, I advise you to follow them in order.</strong></strong></p><hr><h1 id="movies">Movies</h1><p>This is probably one of the most classical project ideas. Simply put, the website offers the user a list of movies they can watch.</p><p>The features of the website are basic enough. You can browse all movies available, search through movies, or browse them by category. If you are logged in, you can add a comment or rate the movie. Also, you can offer news about the movies or the actors. Any feature you can think of is possible.</p><p><strong><strong>What you should focus on: </strong></strong>The main focus is on the admin’s dashboard. The admin is the person that adds, deletes, or edits movies, news, users or comments. If this is your first time developing a project with an admin’s dashboard, then that should be your main focus.</p><hr><h1 id="online-bookstore">Online bookstore</h1><p>This is somewhat similar to the previous project. Create a website that shows the user a list of available books they can buy.</p><p>If you don’t want to implement the payment part, you don’t have to. You can simulate the buying experience and represent it with a simple email sent to the user indicating what items they have bought.</p><p><strong><strong>What you should focus on:</strong></strong> Many of the features of this website are similar to the ones in the previous project. So, try to implement them differently while providing a seamless user experience. If you haven’t used AJAX before or you’re not very good at it, I advise you to learn how to use it in this website. Also, try to focus on security. Learn more about form validations, securing data before inserting them into the database, and other ways to make sure your website is secure.</p><hr><h1 id="tests-generator">Tests Generator</h1><p>This website can offer many features for users. The main feature is that it gives a user the ability to create a multiple choice test and view people’s answers or scores.</p><p>You can add several features to this website. For example, a user that creates a test can make it public or private (accessed by a list of people specified by the user). Another example is that a user can view charts of the questions most answered correctly or least answered correctly. There are so many others as well.</p><p><strong><strong>What you should focus on:</strong></strong> This project has more logic than the previous two. Focus in this one on how to implement the main and additional features in the most efficient ways. Also, make sure to implement authorization (which user can see what).</p><hr><h1 id="top-ten-lists">Top Ten Lists</h1><p>This is a website that I personally worked on to improve my knowledge of <a href="https://reactjs.org/" rel="noopener nofollow">React</a>, but you can create it with the basic and fundamental programming languages.</p><p>Simply, this website lets users create top ten lists about any topic they want. Additional features are users interacting with each other’s lists, voting on each other’s lists, messaging each other, among a lot of other features.</p><p><strong><strong>What you should focus on:</strong></strong> A feature you can learn how to implement is giving users the ability to register or login with their social media accounts. You can try Google, Facebook, or Twitter. Another thing you can focus on is learning <a href="https://getbootstrap.com/" rel="noopener nofollow">Bootstrap</a> or <a href="https://jquery.com/" rel="noopener nofollow">jQuery</a> or both. Both of them are very important and can make your projects (and life) easier.</p><hr><h1 id="budget-tracker">Budget Tracker</h1><p>A very useful website. The main point of this website is to help users manage their expenses and incomes.</p><p>Some features that can be added to the website are calculating profits, informing the user what are their biggest expenses and how they can save up. You can also generate reports for the user.</p><p><strong><strong>What you should focus on: </strong></strong>on this website, focus on making things simple. This website is about helping the user, and the best way you can help them is making the website easy to use. Whether it’s the design or how a user can do a simple or big operation, make it as simple as possible.</p><hr><h1 id="school-management">School Management</h1><p>A very required project by schools and institutes. It’s mostly required as a software, but some need it as a website (run locally, mostly) as well.</p><p>This website gives users the ability to store, edit and view students and teachers’ information. The school can also manage their finances and their curriculum plans, among other features.</p><p>An institute once asked me to add charts that analyze incomes, expenses, number of registered users compared with other users, etc… You can implement that as well.</p><p><strong><strong>What you should focus on: </strong></strong>this website’s core focus is on data. A school will focus mainly on how to view the data and deal with it quickly and efficiently. Another important part is creating backup. Find a way to give the school the ability to create a backup of their data.</p><p><strong><strong>Tip: </strong></strong>an easy way to generate charts is through <a href="https://developers.google.com/chart/" rel="noopener nofollow">Google’s chart web service</a>.</p><hr><h1 id="conclusion">Conclusion</h1><p>This was a list of a few website ideas you can use to increase your knowledge and skills. There are so many more ideas you can think of to create, but this is merely to give you a head start.</p><p><strong><strong>Your opinion: </strong></strong>what other ideas can beginners use to create websites and improve their skills?</p></hr></hr></hr></hr></hr></hr></hr></hr>]]></content:encoded></item></channel></rss>